1 | /* |
2 | * Copyright (C) 2004-2007 Justin Karneges <justin@affinix.com> |
3 | * Copyright (C) 2004-2006 Brad Hards <bradh@frogmouth.net> |
4 | * Copyright (C) 2013-2016 Ivan Romanov <drizt@land.ru> |
5 | * Copyright (C) 2017 Fabian Vogt <fabian@ritter-vogt.de> |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with this library; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
20 | * |
21 | */ |
22 | |
23 | #include <QDebug> |
24 | #include <QElapsedTimer> |
25 | #include <QtCrypto> |
26 | #include <QtPlugin> |
27 | #include <qcaprovider.h> |
28 | |
29 | #include <openssl/evp.h> |
30 | #include <openssl/hmac.h> |
31 | |
32 | #include <cstdio> |
33 | #include <cstdlib> |
34 | #include <iostream> |
35 | #include <memory> |
36 | |
37 | #include <openssl/err.h> |
38 | #include <openssl/opensslv.h> |
39 | #include <openssl/pem.h> |
40 | #include <openssl/pkcs12.h> |
41 | #include <openssl/rand.h> |
42 | #include <openssl/ssl.h> |
43 | #include <openssl/x509v3.h> |
44 | #ifdef OPENSSL_VERSION_MAJOR |
45 | #include <openssl/provider.h> |
46 | #endif |
47 | |
48 | #include <openssl/kdf.h> |
49 | |
50 | using namespace QCA; |
51 | |
52 | namespace { |
53 | struct DsaDeleter |
54 | { |
55 | void operator()(DSA *pointer) |
56 | { |
57 | if (pointer) |
58 | DSA_free(r: pointer); |
59 | } |
60 | }; |
61 | |
62 | static bool s_legacyProviderAvailable = false; |
63 | } // end of anonymous namespace |
64 | |
65 | namespace opensslQCAPlugin { |
66 | |
67 | //---------------------------------------------------------------------------- |
68 | // Util |
69 | //---------------------------------------------------------------------------- |
70 | static SecureArray bio2buf(BIO *b) |
71 | { |
72 | SecureArray buf; |
73 | while (true) { |
74 | SecureArray block(1024); |
75 | int ret = BIO_read(b, data: block.data(), dlen: block.size()); |
76 | if (ret <= 0) |
77 | break; |
78 | block.resize(size: ret); |
79 | buf.append(a: block); |
80 | if (ret != 1024) |
81 | break; |
82 | } |
83 | BIO_free(a: b); |
84 | return buf; |
85 | } |
86 | |
87 | static QByteArray bio2ba(BIO *b) |
88 | { |
89 | QByteArray buf; |
90 | while (true) { |
91 | QByteArray block(1024, 0); |
92 | int ret = BIO_read(b, data: block.data(), dlen: block.size()); |
93 | if (ret <= 0) |
94 | break; |
95 | block.resize(size: ret); |
96 | buf.append(a: block); |
97 | if (ret != 1024) |
98 | break; |
99 | } |
100 | BIO_free(a: b); |
101 | return buf; |
102 | } |
103 | |
104 | static BigInteger bn2bi(const BIGNUM *n) |
105 | { |
106 | SecureArray buf(BN_num_bytes(n) + 1); |
107 | buf[0] = 0; // positive |
108 | BN_bn2bin(a: n, to: (unsigned char *)buf.data() + 1); |
109 | return BigInteger(buf); |
110 | } |
111 | |
112 | static BigInteger bn2bi_free(BIGNUM *n) |
113 | { |
114 | BigInteger bi = bn2bi(n); |
115 | BN_free(a: n); |
116 | return bi; |
117 | } |
118 | |
119 | static BIGNUM *bi2bn(const BigInteger &n) |
120 | { |
121 | SecureArray buf = n.toArray(); |
122 | return BN_bin2bn(s: (const unsigned char *)buf.data(), len: buf.size(), ret: nullptr); |
123 | } |
124 | |
125 | // take lowest bytes of BIGNUM to fit |
126 | // pad with high byte zeroes to fit |
127 | static SecureArray bn2fixedbuf(const BIGNUM *n, int size) |
128 | { |
129 | SecureArray buf(BN_num_bytes(n)); |
130 | BN_bn2bin(a: n, to: (unsigned char *)buf.data()); |
131 | |
132 | SecureArray out(size); |
133 | memset(s: out.data(), c: 0, n: size); |
134 | int len = qMin(a: size, b: buf.size()); |
135 | memcpy(dest: out.data() + (size - len), src: buf.data(), n: len); |
136 | return out; |
137 | } |
138 | |
139 | static SecureArray dsasig_der_to_raw(const SecureArray &in) |
140 | { |
141 | DSA_SIG *sig = DSA_SIG_new(); |
142 | const unsigned char *inp = (const unsigned char *)in.data(); |
143 | d2i_DSA_SIG(a: &sig, in: &inp, len: in.size()); |
144 | |
145 | const BIGNUM *bnr, *bns; |
146 | DSA_SIG_get0(sig, pr: &bnr, ps: &bns); |
147 | |
148 | SecureArray part_r = bn2fixedbuf(n: bnr, size: 20); |
149 | SecureArray part_s = bn2fixedbuf(n: bns, size: 20); |
150 | SecureArray result; |
151 | result.append(a: part_r); |
152 | result.append(a: part_s); |
153 | |
154 | DSA_SIG_free(a: sig); |
155 | return result; |
156 | } |
157 | |
158 | static SecureArray dsasig_raw_to_der(const SecureArray &in) |
159 | { |
160 | if (in.size() != 40) |
161 | return SecureArray(); |
162 | |
163 | DSA_SIG *sig = DSA_SIG_new(); |
164 | SecureArray part_r(20); |
165 | BIGNUM *bnr; |
166 | SecureArray part_s(20); |
167 | BIGNUM *bns; |
168 | memcpy(dest: part_r.data(), src: in.data(), n: 20); |
169 | memcpy(dest: part_s.data(), src: in.data() + 20, n: 20); |
170 | bnr = BN_bin2bn(s: (const unsigned char *)part_r.data(), len: part_r.size(), ret: nullptr); |
171 | bns = BN_bin2bn(s: (const unsigned char *)part_s.data(), len: part_s.size(), ret: nullptr); |
172 | |
173 | if (DSA_SIG_set0(sig, r: bnr, s: bns) == 0) |
174 | return SecureArray(); |
175 | // Not documented what happens in the failure case, free bnr and bns? |
176 | |
177 | int len = i2d_DSA_SIG(a: sig, out: nullptr); |
178 | SecureArray result(len); |
179 | unsigned char *p = (unsigned char *)result.data(); |
180 | i2d_DSA_SIG(a: sig, out: &p); |
181 | |
182 | DSA_SIG_free(a: sig); |
183 | return result; |
184 | } |
185 | |
186 | static int passphrase_cb(char *buf, int size, int rwflag, void *u) |
187 | { |
188 | Q_UNUSED(buf); |
189 | Q_UNUSED(size); |
190 | Q_UNUSED(rwflag); |
191 | Q_UNUSED(u); |
192 | return 0; |
193 | } |
194 | |
195 | /*static bool is_basic_constraint(const ConstraintType &t) |
196 | { |
197 | bool basic = false; |
198 | switch(t.known()) |
199 | { |
200 | case DigitalSignature: |
201 | case NonRepudiation: |
202 | case KeyEncipherment: |
203 | case DataEncipherment: |
204 | case KeyAgreement: |
205 | case KeyCertificateSign: |
206 | case CRLSign: |
207 | case EncipherOnly: |
208 | case DecipherOnly: |
209 | basic = true; |
210 | break; |
211 | |
212 | case ServerAuth: |
213 | case ClientAuth: |
214 | case CodeSigning: |
215 | case EmailProtection: |
216 | case IPSecEndSystem: |
217 | case IPSecTunnel: |
218 | case IPSecUser: |
219 | case TimeStamping: |
220 | case OCSPSigning: |
221 | break; |
222 | } |
223 | return basic; |
224 | } |
225 | |
226 | static Constraints basic_only(const Constraints &list) |
227 | { |
228 | Constraints out; |
229 | for(int n = 0; n < list.count(); ++n) |
230 | { |
231 | if(is_basic_constraint(list[n])) |
232 | out += list[n]; |
233 | } |
234 | return out; |
235 | } |
236 | |
237 | static Constraints ext_only(const Constraints &list) |
238 | { |
239 | Constraints out; |
240 | for(int n = 0; n < list.count(); ++n) |
241 | { |
242 | if(!is_basic_constraint(list[n])) |
243 | out += list[n]; |
244 | } |
245 | return out; |
246 | }*/ |
247 | |
248 | // logic from Botan |
249 | /*static Constraints find_constraints(const PKeyContext &key, const Constraints &orig) |
250 | { |
251 | Constraints constraints; |
252 | |
253 | if(key.key()->type() == PKey::RSA) |
254 | constraints += KeyEncipherment; |
255 | |
256 | if(key.key()->type() == PKey::DH) |
257 | constraints += KeyAgreement; |
258 | |
259 | if(key.key()->type() == PKey::RSA || key.key()->type() == PKey::DSA) |
260 | { |
261 | constraints += DigitalSignature; |
262 | constraints += NonRepudiation; |
263 | } |
264 | |
265 | Constraints limits = basic_only(orig); |
266 | Constraints the_rest = ext_only(orig); |
267 | |
268 | if(!limits.isEmpty()) |
269 | { |
270 | Constraints reduced; |
271 | for(int n = 0; n < constraints.count(); ++n) |
272 | { |
273 | if(limits.contains(constraints[n])) |
274 | reduced += constraints[n]; |
275 | } |
276 | constraints = reduced; |
277 | } |
278 | |
279 | constraints += the_rest; |
280 | |
281 | return constraints; |
282 | }*/ |
283 | |
284 | static void try_add_name_item(X509_NAME **name, int nid, const QString &val) |
285 | { |
286 | if (val.isEmpty()) |
287 | return; |
288 | const QByteArray buf = val.toLatin1(); |
289 | if (!(*name)) |
290 | *name = X509_NAME_new(); |
291 | X509_NAME_add_entry_by_NID(name: *name, nid, MBSTRING_ASC, bytes: (const unsigned char *)buf.data(), len: buf.size(), loc: -1, set: 0); |
292 | } |
293 | |
294 | static X509_NAME *new_cert_name(const CertificateInfo &info) |
295 | { |
296 | X509_NAME *name = nullptr; |
297 | // FIXME support multiple items of each type |
298 | try_add_name_item(name: &name, NID_commonName, val: info.value(key: CommonName)); |
299 | try_add_name_item(name: &name, NID_countryName, val: info.value(key: Country)); |
300 | try_add_name_item(name: &name, NID_localityName, val: info.value(key: Locality)); |
301 | try_add_name_item(name: &name, NID_stateOrProvinceName, val: info.value(key: State)); |
302 | try_add_name_item(name: &name, NID_organizationName, val: info.value(key: Organization)); |
303 | try_add_name_item(name: &name, NID_organizationalUnitName, val: info.value(key: OrganizationalUnit)); |
304 | return name; |
305 | } |
306 | |
307 | static void try_get_name_item(X509_NAME *name, int nid, const CertificateInfoType &t, CertificateInfo *info) |
308 | { |
309 | int loc; |
310 | loc = -1; |
311 | while ((loc = X509_NAME_get_index_by_NID(name, nid, lastpos: loc)) != -1) { |
312 | X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, loc); |
313 | ASN1_STRING *data = X509_NAME_ENTRY_get_data(ne); |
314 | QByteArray cs((const char *)data->data, data->length); |
315 | info->insert(key: t, value: QString::fromLatin1(ba: cs)); |
316 | } |
317 | } |
318 | |
319 | static void |
320 | try_get_name_item_by_oid(X509_NAME *name, const QString &oidText, const CertificateInfoType &t, CertificateInfo *info) |
321 | { |
322 | ASN1_OBJECT *oid = OBJ_txt2obj(s: oidText.toLatin1().data(), no_name: 1); // 1 = only accept dotted input |
323 | if (!oid) |
324 | return; |
325 | |
326 | int loc; |
327 | loc = -1; |
328 | while ((loc = X509_NAME_get_index_by_OBJ(name, obj: oid, lastpos: loc)) != -1) { |
329 | X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, loc); |
330 | ASN1_STRING *data = X509_NAME_ENTRY_get_data(ne); |
331 | QByteArray cs((const char *)data->data, data->length); |
332 | info->insert(key: t, value: QString::fromLatin1(ba: cs)); |
333 | qDebug() << "oid: " << oidText << ", result: " << cs; |
334 | } |
335 | ASN1_OBJECT_free(a: oid); |
336 | } |
337 | |
338 | static CertificateInfo get_cert_name(X509_NAME *name) |
339 | { |
340 | CertificateInfo info; |
341 | try_get_name_item(name, NID_commonName, t: CommonName, info: &info); |
342 | try_get_name_item(name, NID_countryName, t: Country, info: &info); |
343 | try_get_name_item_by_oid(name, QStringLiteral("1.3.6.1.4.1.311.60.2.1.3" ), t: IncorporationCountry, info: &info); |
344 | try_get_name_item(name, NID_localityName, t: Locality, info: &info); |
345 | try_get_name_item_by_oid(name, QStringLiteral("1.3.6.1.4.1.311.60.2.1.1" ), t: IncorporationLocality, info: &info); |
346 | try_get_name_item(name, NID_stateOrProvinceName, t: State, info: &info); |
347 | try_get_name_item_by_oid(name, QStringLiteral("1.3.6.1.4.1.311.60.2.1.2" ), t: IncorporationState, info: &info); |
348 | try_get_name_item(name, NID_organizationName, t: Organization, info: &info); |
349 | try_get_name_item(name, NID_organizationalUnitName, t: OrganizationalUnit, info: &info); |
350 | |
351 | // legacy email |
352 | { |
353 | CertificateInfo p9_info; |
354 | try_get_name_item(name, NID_pkcs9_emailAddress, t: EmailLegacy, info: &p9_info); |
355 | const QList<QString> emails = info.values(key: Email); |
356 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) |
357 | QMultiMapIterator<CertificateInfoType, QString> it(p9_info); |
358 | #else |
359 | QMapIterator<CertificateInfoType, QString> it(p9_info); |
360 | #endif |
361 | while (it.hasNext()) { |
362 | it.next(); |
363 | if (!emails.contains(str: it.value())) |
364 | info.insert(key: Email, value: it.value()); |
365 | } |
366 | } |
367 | |
368 | return info; |
369 | } |
370 | |
371 | static X509_EXTENSION *new_subject_key_id(X509 *cert) |
372 | { |
373 | X509V3_CTX ctx; |
374 | X509V3_set_ctx_nodb(&ctx); |
375 | X509V3_set_ctx(ctx: &ctx, issuer: nullptr, subject: cert, req: nullptr, crl: nullptr, flags: 0); |
376 | X509_EXTENSION *ex = X509V3_EXT_conf_nid(conf: nullptr, ctx: &ctx, NID_subject_key_identifier, value: (char *)"hash" ); |
377 | return ex; |
378 | } |
379 | |
380 | static X509_EXTENSION *new_basic_constraints(bool ca, int pathlen) |
381 | { |
382 | BASIC_CONSTRAINTS *bs = BASIC_CONSTRAINTS_new(); |
383 | bs->ca = (ca ? 1 : 0); |
384 | bs->pathlen = ASN1_INTEGER_new(); |
385 | ASN1_INTEGER_set(a: bs->pathlen, v: pathlen); |
386 | |
387 | X509_EXTENSION *ex = X509V3_EXT_i2d(NID_basic_constraints, crit: 1, ext_struc: bs); // 1 = critical |
388 | BASIC_CONSTRAINTS_free(a: bs); |
389 | return ex; |
390 | } |
391 | |
392 | static void get_basic_constraints(X509_EXTENSION *ex, bool *ca, int *pathlen) |
393 | { |
394 | BASIC_CONSTRAINTS *bs = (BASIC_CONSTRAINTS *)X509V3_EXT_d2i(ext: ex); |
395 | *ca = (bs->ca ? true : false); |
396 | if (bs->pathlen) |
397 | *pathlen = ASN1_INTEGER_get(a: bs->pathlen); |
398 | else |
399 | *pathlen = 0; |
400 | BASIC_CONSTRAINTS_free(a: bs); |
401 | } |
402 | |
403 | enum ConstraintBit |
404 | { |
405 | Bit_DigitalSignature = 0, |
406 | Bit_NonRepudiation = 1, |
407 | Bit_KeyEncipherment = 2, |
408 | Bit_DataEncipherment = 3, |
409 | Bit_KeyAgreement = 4, |
410 | Bit_KeyCertificateSign = 5, |
411 | Bit_CRLSign = 6, |
412 | Bit_EncipherOnly = 7, |
413 | Bit_DecipherOnly = 8 |
414 | }; |
415 | |
416 | static QByteArray ipaddress_string_to_bytes(const QString &) |
417 | { |
418 | return QByteArray(4, 0); |
419 | } |
420 | |
421 | static GENERAL_NAME *new_general_name(const CertificateInfoType &t, const QString &val) |
422 | { |
423 | GENERAL_NAME *name = nullptr; |
424 | switch (t.known()) { |
425 | case Email: |
426 | { |
427 | const QByteArray buf = val.toLatin1(); |
428 | |
429 | ASN1_IA5STRING *str = ASN1_IA5STRING_new(); |
430 | ASN1_STRING_set(str: (ASN1_STRING *)str, data: (const unsigned char *)buf.data(), len: buf.size()); |
431 | |
432 | name = GENERAL_NAME_new(); |
433 | name->type = GEN_EMAIL; |
434 | name->d.rfc822Name = str; |
435 | break; |
436 | } |
437 | case URI: |
438 | { |
439 | const QByteArray buf = val.toLatin1(); |
440 | |
441 | ASN1_IA5STRING *str = ASN1_IA5STRING_new(); |
442 | ASN1_STRING_set(str: (ASN1_STRING *)str, data: (const unsigned char *)buf.data(), len: buf.size()); |
443 | |
444 | name = GENERAL_NAME_new(); |
445 | name->type = GEN_URI; |
446 | name->d.uniformResourceIdentifier = str; |
447 | break; |
448 | } |
449 | case DNS: |
450 | { |
451 | const QByteArray buf = val.toLatin1(); |
452 | |
453 | ASN1_IA5STRING *str = ASN1_IA5STRING_new(); |
454 | ASN1_STRING_set(str: (ASN1_STRING *)str, data: (const unsigned char *)buf.data(), len: buf.size()); |
455 | |
456 | name = GENERAL_NAME_new(); |
457 | name->type = GEN_DNS; |
458 | name->d.dNSName = str; |
459 | break; |
460 | } |
461 | case IPAddress: |
462 | { |
463 | const QByteArray buf = ipaddress_string_to_bytes(val); |
464 | |
465 | ASN1_OCTET_STRING *str = ASN1_OCTET_STRING_new(); |
466 | ASN1_STRING_set(str: (ASN1_STRING *)str, data: (const unsigned char *)buf.data(), len: buf.size()); |
467 | |
468 | name = GENERAL_NAME_new(); |
469 | name->type = GEN_IPADD; |
470 | name->d.iPAddress = str; |
471 | break; |
472 | } |
473 | case XMPP: |
474 | { |
475 | const QByteArray buf = val.toUtf8(); |
476 | |
477 | ASN1_UTF8STRING *str = ASN1_UTF8STRING_new(); |
478 | ASN1_STRING_set(str: (ASN1_STRING *)str, data: (const unsigned char *)buf.data(), len: buf.size()); |
479 | |
480 | ASN1_TYPE *at = ASN1_TYPE_new(); |
481 | at->type = V_ASN1_UTF8STRING; |
482 | at->value.utf8string = str; |
483 | |
484 | OTHERNAME *other = OTHERNAME_new(); |
485 | other->type_id = OBJ_txt2obj(s: "1.3.6.1.5.5.7.8.5" , no_name: 1); // 1 = only accept dotted input |
486 | other->value = at; |
487 | |
488 | name = GENERAL_NAME_new(); |
489 | name->type = GEN_OTHERNAME; |
490 | name->d.otherName = other; |
491 | break; |
492 | } |
493 | default: |
494 | break; |
495 | } |
496 | return name; |
497 | } |
498 | |
499 | static void try_add_general_name(GENERAL_NAMES **gn, const CertificateInfoType &t, const QString &val) |
500 | { |
501 | if (val.isEmpty()) |
502 | return; |
503 | GENERAL_NAME *name = new_general_name(t, val); |
504 | if (name) { |
505 | if (!(*gn)) |
506 | *gn = sk_GENERAL_NAME_new_null(); |
507 | sk_GENERAL_NAME_push(*gn, name); |
508 | } |
509 | } |
510 | |
511 | static X509_EXTENSION *new_cert_subject_alt_name(const CertificateInfo &info) |
512 | { |
513 | GENERAL_NAMES *gn = nullptr; |
514 | // FIXME support multiple items of each type |
515 | try_add_general_name(gn: &gn, t: Email, val: info.value(key: Email)); |
516 | try_add_general_name(gn: &gn, t: URI, val: info.value(key: URI)); |
517 | try_add_general_name(gn: &gn, t: DNS, val: info.value(key: DNS)); |
518 | try_add_general_name(gn: &gn, t: IPAddress, val: info.value(key: IPAddress)); |
519 | try_add_general_name(gn: &gn, t: XMPP, val: info.value(key: XMPP)); |
520 | if (!gn) |
521 | return nullptr; |
522 | |
523 | X509_EXTENSION *ex = X509V3_EXT_i2d(NID_subject_alt_name, crit: 0, ext_struc: gn); |
524 | sk_GENERAL_NAME_pop_free(gn, GENERAL_NAME_free); |
525 | return ex; |
526 | } |
527 | |
528 | static GENERAL_NAME *find_next_general_name(GENERAL_NAMES *names, int type, int *pos) |
529 | { |
530 | int temp = *pos; |
531 | GENERAL_NAME *gn = nullptr; |
532 | *pos = -1; |
533 | for (int n = temp; n < sk_GENERAL_NAME_num(names); ++n) { |
534 | GENERAL_NAME *i = sk_GENERAL_NAME_value(names, n); |
535 | if (i->type == type) { |
536 | gn = i; |
537 | *pos = n; |
538 | break; |
539 | } |
540 | } |
541 | return gn; |
542 | } |
543 | |
544 | static QByteArray qca_ASN1_STRING_toByteArray(ASN1_STRING *x) |
545 | { |
546 | return QByteArray(reinterpret_cast<const char *>(ASN1_STRING_get0_data(x)), ASN1_STRING_length(x)); |
547 | } |
548 | |
549 | static void try_get_general_name(GENERAL_NAMES *names, const CertificateInfoType &t, CertificateInfo *info) |
550 | { |
551 | switch (t.known()) { |
552 | case Email: |
553 | { |
554 | int pos = 0; |
555 | while (pos != -1) { |
556 | GENERAL_NAME *gn = find_next_general_name(names, GEN_EMAIL, pos: &pos); |
557 | if (pos != -1) { |
558 | const QByteArray cs = qca_ASN1_STRING_toByteArray(x: gn->d.rfc822Name); |
559 | info->insert(key: t, value: QString::fromLatin1(ba: cs)); |
560 | ++pos; |
561 | } |
562 | } |
563 | break; |
564 | } |
565 | case URI: |
566 | { |
567 | int pos = 0; |
568 | while (pos != -1) { |
569 | GENERAL_NAME *gn = find_next_general_name(names, GEN_URI, pos: &pos); |
570 | if (pos != -1) { |
571 | const QByteArray cs = qca_ASN1_STRING_toByteArray(x: gn->d.uniformResourceIdentifier); |
572 | info->insert(key: t, value: QString::fromLatin1(ba: cs)); |
573 | ++pos; |
574 | } |
575 | } |
576 | break; |
577 | } |
578 | case DNS: |
579 | { |
580 | int pos = 0; |
581 | while (pos != -1) { |
582 | GENERAL_NAME *gn = find_next_general_name(names, GEN_DNS, pos: &pos); |
583 | if (pos != -1) { |
584 | const QByteArray cs = qca_ASN1_STRING_toByteArray(x: gn->d.dNSName); |
585 | info->insert(key: t, value: QString::fromLatin1(ba: cs)); |
586 | ++pos; |
587 | } |
588 | } |
589 | break; |
590 | } |
591 | case IPAddress: |
592 | { |
593 | int pos = 0; |
594 | while (pos != -1) { |
595 | GENERAL_NAME *gn = find_next_general_name(names, GEN_IPADD, pos: &pos); |
596 | if (pos != -1) { |
597 | ASN1_OCTET_STRING *str = gn->d.iPAddress; |
598 | const QByteArray buf = qca_ASN1_STRING_toByteArray(x: str); |
599 | |
600 | QString out; |
601 | // IPv4 (TODO: handle IPv6) |
602 | if (buf.size() == 4) { |
603 | out = QStringLiteral("0.0.0.0" ); |
604 | } else |
605 | break; |
606 | info->insert(key: t, value: out); |
607 | ++pos; |
608 | } |
609 | } |
610 | break; |
611 | } |
612 | case XMPP: |
613 | { |
614 | int pos = 0; |
615 | while (pos != -1) { |
616 | GENERAL_NAME *gn = find_next_general_name(names, GEN_OTHERNAME, pos: &pos); |
617 | if (pos != -1) { |
618 | OTHERNAME *other = gn->d.otherName; |
619 | if (!other) |
620 | break; |
621 | |
622 | ASN1_OBJECT *obj = OBJ_txt2obj(s: "1.3.6.1.5.5.7.8.5" , no_name: 1); // 1 = only accept dotted input |
623 | if (OBJ_cmp(a: other->type_id, b: obj) != 0) |
624 | break; |
625 | ASN1_OBJECT_free(a: obj); |
626 | |
627 | ASN1_TYPE *at = other->value; |
628 | if (at->type != V_ASN1_UTF8STRING) |
629 | break; |
630 | |
631 | ASN1_UTF8STRING *str = at->value.utf8string; |
632 | const QByteArray buf = qca_ASN1_STRING_toByteArray(x: str); |
633 | info->insert(key: t, value: QString::fromUtf8(ba: buf)); |
634 | ++pos; |
635 | } |
636 | } |
637 | break; |
638 | } |
639 | default: |
640 | break; |
641 | } |
642 | } |
643 | |
644 | static CertificateInfo get_cert_alt_name(X509_EXTENSION *ex) |
645 | { |
646 | CertificateInfo info; |
647 | GENERAL_NAMES *gn = (GENERAL_NAMES *)X509V3_EXT_d2i(ext: ex); |
648 | try_get_general_name(names: gn, t: Email, info: &info); |
649 | try_get_general_name(names: gn, t: URI, info: &info); |
650 | try_get_general_name(names: gn, t: DNS, info: &info); |
651 | try_get_general_name(names: gn, t: IPAddress, info: &info); |
652 | try_get_general_name(names: gn, t: XMPP, info: &info); |
653 | GENERAL_NAMES_free(a: gn); |
654 | return info; |
655 | } |
656 | |
657 | static X509_EXTENSION *new_cert_key_usage(const Constraints &constraints) |
658 | { |
659 | ASN1_BIT_STRING *keyusage = nullptr; |
660 | for (int n = 0; n < constraints.count(); ++n) { |
661 | int bit = -1; |
662 | switch (constraints[n].known()) { |
663 | case DigitalSignature: |
664 | bit = Bit_DigitalSignature; |
665 | break; |
666 | case NonRepudiation: |
667 | bit = Bit_NonRepudiation; |
668 | break; |
669 | case KeyEncipherment: |
670 | bit = Bit_KeyEncipherment; |
671 | break; |
672 | case DataEncipherment: |
673 | bit = Bit_DataEncipherment; |
674 | break; |
675 | case KeyAgreement: |
676 | bit = Bit_KeyAgreement; |
677 | break; |
678 | case KeyCertificateSign: |
679 | bit = Bit_KeyCertificateSign; |
680 | break; |
681 | case CRLSign: |
682 | bit = Bit_CRLSign; |
683 | break; |
684 | case EncipherOnly: |
685 | bit = Bit_EncipherOnly; |
686 | break; |
687 | case DecipherOnly: |
688 | bit = Bit_DecipherOnly; |
689 | break; |
690 | default: |
691 | break; |
692 | } |
693 | if (bit != -1) { |
694 | if (!keyusage) |
695 | keyusage = ASN1_BIT_STRING_new(); |
696 | ASN1_BIT_STRING_set_bit(a: keyusage, n: bit, value: 1); |
697 | } |
698 | } |
699 | if (!keyusage) |
700 | return nullptr; |
701 | |
702 | X509_EXTENSION *ex = X509V3_EXT_i2d(NID_key_usage, crit: 1, ext_struc: keyusage); // 1 = critical |
703 | ASN1_BIT_STRING_free(a: keyusage); |
704 | return ex; |
705 | } |
706 | |
707 | static Constraints get_cert_key_usage(X509_EXTENSION *ex) |
708 | { |
709 | Constraints constraints; |
710 | int bit_table[9] = {DigitalSignature, |
711 | NonRepudiation, |
712 | KeyEncipherment, |
713 | DataEncipherment, |
714 | KeyAgreement, |
715 | KeyCertificateSign, |
716 | CRLSign, |
717 | EncipherOnly, |
718 | DecipherOnly}; |
719 | |
720 | ASN1_BIT_STRING *keyusage = (ASN1_BIT_STRING *)X509V3_EXT_d2i(ext: ex); |
721 | for (int n = 0; n < 9; ++n) { |
722 | if (ASN1_BIT_STRING_get_bit(a: keyusage, n)) |
723 | constraints += ConstraintType((ConstraintTypeKnown)bit_table[n]); |
724 | } |
725 | ASN1_BIT_STRING_free(a: keyusage); |
726 | return constraints; |
727 | } |
728 | |
729 | static X509_EXTENSION *new_cert_ext_key_usage(const Constraints &constraints) |
730 | { |
731 | EXTENDED_KEY_USAGE *extkeyusage = nullptr; |
732 | for (int n = 0; n < constraints.count(); ++n) { |
733 | int nid = -1; |
734 | // TODO: don't use known/nid, and instead just use OIDs |
735 | switch (constraints[n].known()) { |
736 | case ServerAuth: |
737 | nid = NID_server_auth; |
738 | break; |
739 | case ClientAuth: |
740 | nid = NID_client_auth; |
741 | break; |
742 | case CodeSigning: |
743 | nid = NID_code_sign; |
744 | break; |
745 | case EmailProtection: |
746 | nid = NID_email_protect; |
747 | break; |
748 | case IPSecEndSystem: |
749 | nid = NID_ipsecEndSystem; |
750 | break; |
751 | case IPSecTunnel: |
752 | nid = NID_ipsecTunnel; |
753 | break; |
754 | case IPSecUser: |
755 | nid = NID_ipsecUser; |
756 | break; |
757 | case TimeStamping: |
758 | nid = NID_time_stamp; |
759 | break; |
760 | case OCSPSigning: |
761 | nid = NID_OCSP_sign; |
762 | break; |
763 | default: |
764 | break; |
765 | } |
766 | if (nid != -1) { |
767 | if (!extkeyusage) |
768 | extkeyusage = sk_ASN1_OBJECT_new_null(); |
769 | ASN1_OBJECT *obj = OBJ_nid2obj(n: nid); |
770 | sk_ASN1_OBJECT_push(extkeyusage, obj); |
771 | } |
772 | } |
773 | if (!extkeyusage) |
774 | return nullptr; |
775 | |
776 | X509_EXTENSION *ex = X509V3_EXT_i2d(NID_ext_key_usage, crit: 0, ext_struc: extkeyusage); // 0 = not critical |
777 | sk_ASN1_OBJECT_pop_free(extkeyusage, ASN1_OBJECT_free); |
778 | return ex; |
779 | } |
780 | |
781 | static Constraints get_cert_ext_key_usage(X509_EXTENSION *ex) |
782 | { |
783 | Constraints constraints; |
784 | |
785 | EXTENDED_KEY_USAGE *extkeyusage = (EXTENDED_KEY_USAGE *)X509V3_EXT_d2i(ext: ex); |
786 | for (int n = 0; n < sk_ASN1_OBJECT_num(extkeyusage); ++n) { |
787 | ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(extkeyusage, n); |
788 | int nid = OBJ_obj2nid(o: obj); |
789 | if (nid == NID_undef) |
790 | continue; |
791 | |
792 | // TODO: don't use known/nid, and instead just use OIDs |
793 | int t = -1; |
794 | switch (nid) { |
795 | case NID_server_auth: |
796 | t = ServerAuth; |
797 | break; |
798 | case NID_client_auth: |
799 | t = ClientAuth; |
800 | break; |
801 | case NID_code_sign: |
802 | t = CodeSigning; |
803 | break; |
804 | case NID_email_protect: |
805 | t = EmailProtection; |
806 | break; |
807 | case NID_ipsecEndSystem: |
808 | t = IPSecEndSystem; |
809 | break; |
810 | case NID_ipsecTunnel: |
811 | t = IPSecTunnel; |
812 | break; |
813 | case NID_ipsecUser: |
814 | t = IPSecUser; |
815 | break; |
816 | case NID_time_stamp: |
817 | t = TimeStamping; |
818 | break; |
819 | case NID_OCSP_sign: |
820 | t = OCSPSigning; |
821 | break; |
822 | }; |
823 | |
824 | if (t == -1) |
825 | continue; |
826 | |
827 | constraints.append(t: ConstraintType((ConstraintTypeKnown)t)); |
828 | } |
829 | sk_ASN1_OBJECT_pop_free(extkeyusage, ASN1_OBJECT_free); |
830 | return constraints; |
831 | } |
832 | |
833 | static X509_EXTENSION *new_cert_policies(const QStringList &policies) |
834 | { |
835 | STACK_OF(POLICYINFO) *pols = nullptr; |
836 | for (int n = 0; n < policies.count(); ++n) { |
837 | const QByteArray cs = policies[n].toLatin1(); |
838 | ASN1_OBJECT *obj = OBJ_txt2obj(s: cs.data(), no_name: 1); // 1 = only accept dotted input |
839 | if (!obj) |
840 | continue; |
841 | if (!pols) |
842 | pols = sk_POLICYINFO_new_null(); |
843 | POLICYINFO *pol = POLICYINFO_new(); |
844 | pol->policyid = obj; |
845 | sk_POLICYINFO_push(pols, pol); |
846 | } |
847 | if (!pols) |
848 | return nullptr; |
849 | |
850 | X509_EXTENSION *ex = X509V3_EXT_i2d(NID_certificate_policies, crit: 0, ext_struc: pols); // 0 = not critical |
851 | sk_POLICYINFO_pop_free(pols, POLICYINFO_free); |
852 | return ex; |
853 | } |
854 | |
855 | static QStringList get_cert_policies(X509_EXTENSION *ex) |
856 | { |
857 | QStringList out; |
858 | STACK_OF(POLICYINFO) *pols = (STACK_OF(POLICYINFO) *)X509V3_EXT_d2i(ext: ex); |
859 | for (int n = 0; n < sk_POLICYINFO_num(pols); ++n) { |
860 | POLICYINFO *pol = sk_POLICYINFO_value(pols, n); |
861 | QByteArray buf(128, 0); |
862 | const auto len = OBJ_obj2txt(buf: (char *)buf.data(), buf_len: buf.size(), a: pol->policyid, no_name: 1); // 1 = only accept dotted input |
863 | if (len > 0) |
864 | out += QString::fromLatin1(ba: buf.left(len)); |
865 | } |
866 | sk_POLICYINFO_pop_free(pols, POLICYINFO_free); |
867 | return out; |
868 | } |
869 | |
870 | static QByteArray get_cert_subject_key_id(X509_EXTENSION *ex) |
871 | { |
872 | ASN1_OCTET_STRING *skid = (ASN1_OCTET_STRING *)X509V3_EXT_d2i(ext: ex); |
873 | const QByteArray out = qca_ASN1_STRING_toByteArray(x: skid); |
874 | ASN1_OCTET_STRING_free(a: skid); |
875 | return out; |
876 | } |
877 | |
878 | // If you get any more crashes in this code, please provide a copy |
879 | // of the cert to bradh AT frogmouth.net |
880 | static QByteArray get_cert_issuer_key_id(X509_EXTENSION *ex) |
881 | { |
882 | AUTHORITY_KEYID *akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext: ex); |
883 | QByteArray out; |
884 | if (akid->keyid) |
885 | out = qca_ASN1_STRING_toByteArray(x: akid->keyid); |
886 | AUTHORITY_KEYID_free(a: akid); |
887 | return out; |
888 | } |
889 | |
890 | static Validity convert_verify_error(int err) |
891 | { |
892 | // TODO: ErrorExpiredCA |
893 | Validity rc; |
894 | switch (err) { |
895 | case X509_V_ERR_CERT_REJECTED: |
896 | rc = ErrorRejected; |
897 | break; |
898 | case X509_V_ERR_CERT_UNTRUSTED: |
899 | rc = ErrorUntrusted; |
900 | break; |
901 | case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: |
902 | case X509_V_ERR_CERT_SIGNATURE_FAILURE: |
903 | case X509_V_ERR_CRL_SIGNATURE_FAILURE: |
904 | case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: |
905 | case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: |
906 | rc = ErrorSignatureFailed; |
907 | break; |
908 | case X509_V_ERR_INVALID_CA: |
909 | case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: |
910 | case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: |
911 | case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: |
912 | rc = ErrorInvalidCA; |
913 | break; |
914 | case X509_V_ERR_INVALID_PURPOSE: // note: not used by store verify |
915 | rc = ErrorInvalidPurpose; |
916 | break; |
917 | case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: |
918 | case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: |
919 | rc = ErrorSelfSigned; |
920 | break; |
921 | case X509_V_ERR_CERT_REVOKED: |
922 | rc = ErrorRevoked; |
923 | break; |
924 | case X509_V_ERR_PATH_LENGTH_EXCEEDED: |
925 | rc = ErrorPathLengthExceeded; |
926 | break; |
927 | case X509_V_ERR_CERT_NOT_YET_VALID: |
928 | case X509_V_ERR_CERT_HAS_EXPIRED: |
929 | case X509_V_ERR_CRL_NOT_YET_VALID: |
930 | case X509_V_ERR_CRL_HAS_EXPIRED: |
931 | case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: |
932 | case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: |
933 | case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: |
934 | case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: |
935 | rc = ErrorExpired; |
936 | break; |
937 | case X509_V_ERR_APPLICATION_VERIFICATION: |
938 | case X509_V_ERR_OUT_OF_MEM: |
939 | case X509_V_ERR_UNABLE_TO_GET_CRL: |
940 | case X509_V_ERR_CERT_CHAIN_TOO_LONG: |
941 | default: |
942 | rc = ErrorValidityUnknown; |
943 | break; |
944 | } |
945 | return rc; |
946 | } |
947 | |
948 | EVP_PKEY *qca_d2i_PKCS8PrivateKey(const SecureArray &in, EVP_PKEY **x, pem_password_cb *cb, void *u) |
949 | { |
950 | PKCS8_PRIV_KEY_INFO *p8inf; |
951 | |
952 | // first try unencrypted form |
953 | BIO *bi = BIO_new(type: BIO_s_mem()); |
954 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
955 | p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(bp: bi, p8inf: nullptr); |
956 | BIO_free(a: bi); |
957 | if (!p8inf) { |
958 | X509_SIG *p8; |
959 | |
960 | // now try encrypted form |
961 | bi = BIO_new(type: BIO_s_mem()); |
962 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
963 | p8 = d2i_PKCS8_bio(bp: bi, p8: nullptr); |
964 | BIO_free(a: bi); |
965 | if (!p8) |
966 | return nullptr; |
967 | |
968 | // get passphrase |
969 | char psbuf[PEM_BUFSIZE]; |
970 | int klen; |
971 | if (cb) |
972 | klen = cb(psbuf, PEM_BUFSIZE, 0, u); |
973 | else |
974 | klen = PEM_def_callback(buf: psbuf, PEM_BUFSIZE, rwflag: 0, userdata: u); |
975 | if (klen <= 0) { |
976 | PEMerr(PEM_F_D2I_PKCS8PRIVATEKEY_BIO, PEM_R_BAD_PASSWORD_READ); |
977 | X509_SIG_free(a: p8); |
978 | return nullptr; |
979 | } |
980 | |
981 | // decrypt it |
982 | p8inf = PKCS8_decrypt(p8, pass: psbuf, passlen: klen); |
983 | X509_SIG_free(a: p8); |
984 | if (!p8inf) |
985 | return nullptr; |
986 | } |
987 | |
988 | EVP_PKEY *ret = EVP_PKCS82PKEY(p8: p8inf); |
989 | PKCS8_PRIV_KEY_INFO_free(a: p8inf); |
990 | if (!ret) |
991 | return nullptr; |
992 | if (x) { |
993 | if (*x) |
994 | EVP_PKEY_free(pkey: *x); |
995 | *x = ret; |
996 | } |
997 | return ret; |
998 | } |
999 | |
1000 | class opensslHashContext : public HashContext |
1001 | { |
1002 | Q_OBJECT |
1003 | public: |
1004 | opensslHashContext(const EVP_MD *algorithm, Provider *p, const QString &type) |
1005 | : HashContext(p, type) |
1006 | { |
1007 | m_algorithm = algorithm; |
1008 | m_context = EVP_MD_CTX_new(); |
1009 | EVP_DigestInit(ctx: m_context, type: m_algorithm); |
1010 | } |
1011 | |
1012 | opensslHashContext(const opensslHashContext &other) |
1013 | : HashContext(other) |
1014 | { |
1015 | m_algorithm = other.m_algorithm; |
1016 | m_context = EVP_MD_CTX_new(); |
1017 | EVP_MD_CTX_copy_ex(out: m_context, in: other.m_context); |
1018 | } |
1019 | |
1020 | ~opensslHashContext() override |
1021 | { |
1022 | EVP_MD_CTX_free(ctx: m_context); |
1023 | } |
1024 | |
1025 | void clear() override |
1026 | { |
1027 | EVP_MD_CTX_free(ctx: m_context); |
1028 | m_context = EVP_MD_CTX_new(); |
1029 | EVP_DigestInit(ctx: m_context, type: m_algorithm); |
1030 | } |
1031 | |
1032 | void update(const MemoryRegion &a) override |
1033 | { |
1034 | EVP_DigestUpdate(ctx: m_context, d: (unsigned char *)a.data(), cnt: a.size()); |
1035 | } |
1036 | |
1037 | MemoryRegion final() override |
1038 | { |
1039 | SecureArray a(EVP_MD_size(md: m_algorithm)); |
1040 | EVP_DigestFinal(ctx: m_context, md: (unsigned char *)a.data(), s: nullptr); |
1041 | return a; |
1042 | } |
1043 | |
1044 | Provider::Context *clone() const override |
1045 | { |
1046 | return new opensslHashContext(*this); |
1047 | } |
1048 | |
1049 | protected: |
1050 | const EVP_MD *m_algorithm; |
1051 | EVP_MD_CTX *m_context; |
1052 | }; |
1053 | |
1054 | class opensslPbkdf1Context : public KDFContext |
1055 | { |
1056 | Q_OBJECT |
1057 | public: |
1058 | opensslPbkdf1Context(const EVP_MD *algorithm, Provider *p, const QString &type) |
1059 | : KDFContext(p, type) |
1060 | { |
1061 | Q_ASSERT(s_legacyProviderAvailable); |
1062 | m_algorithm = algorithm; |
1063 | m_context = EVP_MD_CTX_new(); |
1064 | EVP_DigestInit(ctx: m_context, type: m_algorithm); |
1065 | } |
1066 | |
1067 | opensslPbkdf1Context(const opensslPbkdf1Context &other) |
1068 | : KDFContext(other) |
1069 | { |
1070 | m_algorithm = other.m_algorithm; |
1071 | m_context = EVP_MD_CTX_new(); |
1072 | EVP_MD_CTX_copy(out: m_context, in: other.m_context); |
1073 | } |
1074 | |
1075 | ~opensslPbkdf1Context() override |
1076 | { |
1077 | EVP_MD_CTX_free(ctx: m_context); |
1078 | } |
1079 | |
1080 | Provider::Context *clone() const override |
1081 | { |
1082 | return new opensslPbkdf1Context(*this); |
1083 | } |
1084 | |
1085 | SymmetricKey makeKey(const SecureArray &secret, |
1086 | const InitializationVector &salt, |
1087 | unsigned int keyLength, |
1088 | unsigned int iterationCount) override |
1089 | { |
1090 | /* from RFC2898: |
1091 | Steps: |
1092 | |
1093 | 1. If dkLen > 16 for MD2 and MD5, or dkLen > 20 for SHA-1, output |
1094 | "derived key too long" and stop. |
1095 | */ |
1096 | if (keyLength > (unsigned int)EVP_MD_size(md: m_algorithm)) { |
1097 | std::cout << "derived key too long" << std::endl; |
1098 | return SymmetricKey(); |
1099 | } |
1100 | |
1101 | /* |
1102 | 2. Apply the underlying hash function Hash for c iterations to the |
1103 | concatenation of the password P and the salt S, then extract |
1104 | the first dkLen octets to produce a derived key DK: |
1105 | |
1106 | T_1 = Hash (P || S) , |
1107 | T_2 = Hash (T_1) , |
1108 | ... |
1109 | T_c = Hash (T_{c-1}) , |
1110 | DK = Tc<0..dkLen-1> |
1111 | */ |
1112 | // calculate T_1 |
1113 | EVP_DigestUpdate(ctx: m_context, d: (unsigned char *)secret.data(), cnt: secret.size()); |
1114 | EVP_DigestUpdate(ctx: m_context, d: (unsigned char *)salt.data(), cnt: salt.size()); |
1115 | SecureArray a(EVP_MD_size(md: m_algorithm)); |
1116 | EVP_DigestFinal(ctx: m_context, md: (unsigned char *)a.data(), s: nullptr); |
1117 | |
1118 | // calculate T_2 up to T_c |
1119 | for (unsigned int i = 2; i <= iterationCount; ++i) { |
1120 | EVP_DigestInit(ctx: m_context, type: m_algorithm); |
1121 | EVP_DigestUpdate(ctx: m_context, d: (unsigned char *)a.data(), cnt: a.size()); |
1122 | EVP_DigestFinal(ctx: m_context, md: (unsigned char *)a.data(), s: nullptr); |
1123 | } |
1124 | |
1125 | // shrink a to become DK, of the required length |
1126 | a.resize(size: keyLength); |
1127 | |
1128 | /* |
1129 | 3. Output the derived key DK. |
1130 | */ |
1131 | return a; |
1132 | } |
1133 | |
1134 | SymmetricKey makeKey(const SecureArray &secret, |
1135 | const InitializationVector &salt, |
1136 | unsigned int keyLength, |
1137 | int msecInterval, |
1138 | unsigned int *iterationCount) override |
1139 | { |
1140 | Q_ASSERT(iterationCount != nullptr); |
1141 | QElapsedTimer timer; |
1142 | |
1143 | /* from RFC2898: |
1144 | Steps: |
1145 | |
1146 | 1. If dkLen > 16 for MD2 and MD5, or dkLen > 20 for SHA-1, output |
1147 | "derived key too long" and stop. |
1148 | */ |
1149 | if (keyLength > (unsigned int)EVP_MD_size(md: m_algorithm)) { |
1150 | std::cout << "derived key too long" << std::endl; |
1151 | return SymmetricKey(); |
1152 | } |
1153 | |
1154 | /* |
1155 | 2. Apply the underlying hash function Hash for M milliseconds |
1156 | to the concatenation of the password P and the salt S, incrementing c, |
1157 | then extract the first dkLen octets to produce a derived key DK: |
1158 | |
1159 | time from M to 0 |
1160 | T_1 = Hash (P || S) , |
1161 | T_2 = Hash (T_1) , |
1162 | ... |
1163 | T_c = Hash (T_{c-1}) , |
1164 | when time = 0: stop, |
1165 | DK = Tc<0..dkLen-1> |
1166 | */ |
1167 | // calculate T_1 |
1168 | EVP_DigestUpdate(ctx: m_context, d: (unsigned char *)secret.data(), cnt: secret.size()); |
1169 | EVP_DigestUpdate(ctx: m_context, d: (unsigned char *)salt.data(), cnt: salt.size()); |
1170 | SecureArray a(EVP_MD_size(md: m_algorithm)); |
1171 | EVP_DigestFinal(ctx: m_context, md: (unsigned char *)a.data(), s: nullptr); |
1172 | |
1173 | // calculate T_2 up to T_c |
1174 | *iterationCount = 2 - 1; // <- Have to remove 1, unless it computes one |
1175 | timer.start(); // ^ time more than the base function |
1176 | // ^ with the same iterationCount |
1177 | while (timer.elapsed() < msecInterval) { |
1178 | EVP_DigestInit(ctx: m_context, type: m_algorithm); |
1179 | EVP_DigestUpdate(ctx: m_context, d: (unsigned char *)a.data(), cnt: a.size()); |
1180 | EVP_DigestFinal(ctx: m_context, md: (unsigned char *)a.data(), s: nullptr); |
1181 | ++(*iterationCount); |
1182 | } |
1183 | |
1184 | // shrink a to become DK, of the required length |
1185 | a.resize(size: keyLength); |
1186 | |
1187 | /* |
1188 | 3. Output the derived key DK. |
1189 | */ |
1190 | return a; |
1191 | } |
1192 | |
1193 | protected: |
1194 | const EVP_MD *m_algorithm; |
1195 | EVP_MD_CTX *m_context; |
1196 | }; |
1197 | |
1198 | class opensslPbkdf2Context : public KDFContext |
1199 | { |
1200 | Q_OBJECT |
1201 | public: |
1202 | opensslPbkdf2Context(Provider *p, const QString &type) |
1203 | : KDFContext(p, type) |
1204 | { |
1205 | } |
1206 | |
1207 | Provider::Context *clone() const override |
1208 | { |
1209 | return new opensslPbkdf2Context(*this); |
1210 | } |
1211 | |
1212 | SymmetricKey makeKey(const SecureArray &secret, |
1213 | const InitializationVector &salt, |
1214 | unsigned int keyLength, |
1215 | unsigned int iterationCount) override |
1216 | { |
1217 | SecureArray out(keyLength); |
1218 | PKCS5_PBKDF2_HMAC_SHA1(pass: (char *)secret.data(), |
1219 | passlen: secret.size(), |
1220 | salt: (unsigned char *)salt.data(), |
1221 | saltlen: salt.size(), |
1222 | iter: iterationCount, |
1223 | keylen: keyLength, |
1224 | out: (unsigned char *)out.data()); |
1225 | return out; |
1226 | } |
1227 | |
1228 | SymmetricKey makeKey(const SecureArray &secret, |
1229 | const InitializationVector &salt, |
1230 | unsigned int keyLength, |
1231 | int msecInterval, |
1232 | unsigned int *iterationCount) override |
1233 | { |
1234 | Q_ASSERT(iterationCount != nullptr); |
1235 | QElapsedTimer timer; |
1236 | SecureArray out(keyLength); |
1237 | |
1238 | *iterationCount = 0; |
1239 | timer.start(); |
1240 | |
1241 | // PBKDF2 needs an iterationCount itself, unless PBKDF1. |
1242 | // So we need to calculate first the number of iterations for |
1243 | // That time interval, then feed the iterationCounts to PBKDF2 |
1244 | while (timer.elapsed() < msecInterval) { |
1245 | PKCS5_PBKDF2_HMAC_SHA1(pass: (char *)secret.data(), |
1246 | passlen: secret.size(), |
1247 | salt: (unsigned char *)salt.data(), |
1248 | saltlen: salt.size(), |
1249 | iter: 1, |
1250 | keylen: keyLength, |
1251 | out: (unsigned char *)out.data()); |
1252 | ++(*iterationCount); |
1253 | } |
1254 | |
1255 | // Now we can directely call makeKey base function, |
1256 | // as we now have the iterationCount |
1257 | out = makeKey(secret, salt, keyLength, iterationCount: *iterationCount); |
1258 | |
1259 | return out; |
1260 | } |
1261 | |
1262 | protected: |
1263 | }; |
1264 | |
1265 | class opensslHkdfContext : public HKDFContext |
1266 | { |
1267 | Q_OBJECT |
1268 | public: |
1269 | opensslHkdfContext(Provider *p, const QString &type) |
1270 | : HKDFContext(p, type) |
1271 | { |
1272 | } |
1273 | |
1274 | Provider::Context *clone() const override |
1275 | { |
1276 | return new opensslHkdfContext(*this); |
1277 | } |
1278 | |
1279 | SymmetricKey makeKey(const SecureArray &secret, |
1280 | const InitializationVector &salt, |
1281 | const InitializationVector &info, |
1282 | unsigned int keyLength) override |
1283 | { |
1284 | SecureArray out(keyLength); |
1285 | EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, e: nullptr); |
1286 | EVP_PKEY_derive_init(ctx: pctx); |
1287 | EVP_PKEY_CTX_set_hkdf_md(ctx: pctx, md: EVP_sha256()); |
1288 | EVP_PKEY_CTX_set1_hkdf_salt(ctx: pctx, salt: (const unsigned char *)salt.data(), saltlen: int(salt.size())); |
1289 | EVP_PKEY_CTX_set1_hkdf_key(ctx: pctx, key: (const unsigned char *)secret.data(), keylen: int(secret.size())); |
1290 | EVP_PKEY_CTX_add1_hkdf_info(ctx: pctx, info: (const unsigned char *)info.data(), infolen: int(info.size())); |
1291 | size_t outlen = out.size(); |
1292 | EVP_PKEY_derive(ctx: pctx, key: reinterpret_cast<unsigned char *>(out.data()), keylen: &outlen); |
1293 | EVP_PKEY_CTX_free(ctx: pctx); |
1294 | return out; |
1295 | } |
1296 | }; |
1297 | |
1298 | class opensslHMACContext : public MACContext |
1299 | { |
1300 | Q_OBJECT |
1301 | public: |
1302 | opensslHMACContext(const EVP_MD *algorithm, Provider *p, const QString &type) |
1303 | : MACContext(p, type) |
1304 | { |
1305 | m_algorithm = algorithm; |
1306 | m_context = HMAC_CTX_new(); |
1307 | } |
1308 | |
1309 | opensslHMACContext(const opensslHMACContext &other) |
1310 | : MACContext(other) |
1311 | { |
1312 | m_algorithm = other.m_algorithm; |
1313 | m_context = HMAC_CTX_new(); |
1314 | HMAC_CTX_copy(dctx: m_context, sctx: other.m_context); |
1315 | } |
1316 | |
1317 | ~opensslHMACContext() override |
1318 | { |
1319 | HMAC_CTX_free(ctx: m_context); |
1320 | } |
1321 | |
1322 | void setup(const SymmetricKey &key) override |
1323 | { |
1324 | HMAC_Init_ex(ctx: m_context, key: key.data(), len: key.size(), md: m_algorithm, impl: nullptr); |
1325 | } |
1326 | |
1327 | KeyLength keyLength() const override |
1328 | { |
1329 | return anyKeyLength(); |
1330 | } |
1331 | |
1332 | void update(const MemoryRegion &a) override |
1333 | { |
1334 | HMAC_Update(ctx: m_context, data: (unsigned char *)a.data(), len: a.size()); |
1335 | } |
1336 | |
1337 | void final(MemoryRegion *out) override |
1338 | { |
1339 | SecureArray sa(EVP_MD_size(md: m_algorithm), 0); |
1340 | HMAC_Final(ctx: m_context, md: (unsigned char *)sa.data(), len: nullptr); |
1341 | HMAC_CTX_reset(ctx: m_context); |
1342 | *out = sa; |
1343 | } |
1344 | |
1345 | Provider::Context *clone() const override |
1346 | { |
1347 | return new opensslHMACContext(*this); |
1348 | } |
1349 | |
1350 | protected: |
1351 | HMAC_CTX *m_context; |
1352 | const EVP_MD *m_algorithm; |
1353 | }; |
1354 | |
1355 | //---------------------------------------------------------------------------- |
1356 | // EVPKey |
1357 | //---------------------------------------------------------------------------- |
1358 | |
1359 | // note: this class squelches processing errors, since QCA doesn't care about them |
1360 | class EVPKey |
1361 | { |
1362 | public: |
1363 | enum State |
1364 | { |
1365 | Idle, |
1366 | SignActive, |
1367 | SignError, |
1368 | VerifyActive, |
1369 | VerifyError |
1370 | }; |
1371 | EVP_PKEY *pkey; |
1372 | EVP_MD_CTX *mdctx; |
1373 | State state; |
1374 | bool raw_type; |
1375 | SecureArray raw; |
1376 | |
1377 | EVPKey() |
1378 | { |
1379 | pkey = nullptr; |
1380 | raw_type = false; |
1381 | state = Idle; |
1382 | mdctx = EVP_MD_CTX_new(); |
1383 | } |
1384 | |
1385 | EVPKey(const EVPKey &from) |
1386 | { |
1387 | pkey = from.pkey; |
1388 | EVP_PKEY_up_ref(pkey); |
1389 | raw_type = false; |
1390 | state = Idle; |
1391 | mdctx = EVP_MD_CTX_new(); |
1392 | EVP_MD_CTX_copy(out: mdctx, in: from.mdctx); |
1393 | } |
1394 | |
1395 | EVPKey &operator=(const EVPKey &from) = delete; |
1396 | |
1397 | ~EVPKey() |
1398 | { |
1399 | reset(); |
1400 | EVP_MD_CTX_free(ctx: mdctx); |
1401 | } |
1402 | |
1403 | void reset() |
1404 | { |
1405 | if (pkey) |
1406 | EVP_PKEY_free(pkey); |
1407 | pkey = nullptr; |
1408 | raw.clear(); |
1409 | raw_type = false; |
1410 | } |
1411 | |
1412 | void startSign(const EVP_MD *type) |
1413 | { |
1414 | state = SignActive; |
1415 | if (!type) { |
1416 | raw_type = true; |
1417 | raw.clear(); |
1418 | } else { |
1419 | raw_type = false; |
1420 | EVP_MD_CTX_init(mdctx); |
1421 | if (!EVP_SignInit_ex(mdctx, type, nullptr)) |
1422 | state = SignError; |
1423 | } |
1424 | } |
1425 | |
1426 | void startVerify(const EVP_MD *type) |
1427 | { |
1428 | state = VerifyActive; |
1429 | if (!type) { |
1430 | raw_type = true; |
1431 | raw.clear(); |
1432 | } else { |
1433 | raw_type = false; |
1434 | EVP_MD_CTX_init(mdctx); |
1435 | if (!EVP_VerifyInit_ex(mdctx, type, nullptr)) |
1436 | state = VerifyError; |
1437 | } |
1438 | } |
1439 | |
1440 | void update(const MemoryRegion &in) |
1441 | { |
1442 | if (state == SignActive) { |
1443 | if (raw_type) |
1444 | raw += in; |
1445 | else if (!EVP_SignUpdate(mdctx, in.data(), (unsigned int)in.size())) |
1446 | state = SignError; |
1447 | } else if (state == VerifyActive) { |
1448 | if (raw_type) |
1449 | raw += in; |
1450 | else if (!EVP_VerifyUpdate(mdctx, in.data(), (unsigned int)in.size())) |
1451 | state = VerifyError; |
1452 | } |
1453 | } |
1454 | |
1455 | SecureArray endSign() |
1456 | { |
1457 | if (state == SignActive) { |
1458 | SecureArray out(EVP_PKEY_size(pkey)); |
1459 | unsigned int len = out.size(); |
1460 | if (raw_type) { |
1461 | int type = EVP_PKEY_id(pkey); |
1462 | |
1463 | if (type == EVP_PKEY_RSA) { |
1464 | const RSA *rsa = EVP_PKEY_get0_RSA(pkey); |
1465 | if (RSA_private_encrypt(flen: raw.size(), |
1466 | from: (unsigned char *)raw.data(), |
1467 | to: (unsigned char *)out.data(), |
1468 | rsa: (RSA *)rsa, |
1469 | RSA_PKCS1_PADDING) == -1) { |
1470 | state = SignError; |
1471 | return SecureArray(); |
1472 | } |
1473 | } else if (type == EVP_PKEY_DSA) { |
1474 | state = SignError; |
1475 | return SecureArray(); |
1476 | } else { |
1477 | state = SignError; |
1478 | return SecureArray(); |
1479 | } |
1480 | } else { |
1481 | if (!EVP_SignFinal(ctx: mdctx, md: (unsigned char *)out.data(), s: &len, pkey)) { |
1482 | state = SignError; |
1483 | return SecureArray(); |
1484 | } |
1485 | } |
1486 | out.resize(size: len); |
1487 | state = Idle; |
1488 | return out; |
1489 | } else |
1490 | return SecureArray(); |
1491 | } |
1492 | |
1493 | bool endVerify(const SecureArray &sig) |
1494 | { |
1495 | if (state == VerifyActive) { |
1496 | if (raw_type) { |
1497 | SecureArray out(EVP_PKEY_size(pkey)); |
1498 | int len = 0; |
1499 | |
1500 | int type = EVP_PKEY_id(pkey); |
1501 | |
1502 | if (type == EVP_PKEY_RSA) { |
1503 | const RSA *rsa = EVP_PKEY_get0_RSA(pkey); |
1504 | if ((len = RSA_public_decrypt(flen: sig.size(), |
1505 | from: (unsigned char *)sig.data(), |
1506 | to: (unsigned char *)out.data(), |
1507 | rsa: (RSA *)rsa, |
1508 | RSA_PKCS1_PADDING)) == -1) { |
1509 | state = VerifyError; |
1510 | return false; |
1511 | } |
1512 | } else if (type == EVP_PKEY_DSA) { |
1513 | state = VerifyError; |
1514 | return false; |
1515 | } else { |
1516 | state = VerifyError; |
1517 | return false; |
1518 | } |
1519 | |
1520 | out.resize(size: len); |
1521 | |
1522 | if (out != raw) { |
1523 | state = VerifyError; |
1524 | return false; |
1525 | } |
1526 | } else { |
1527 | if (EVP_VerifyFinal(ctx: mdctx, sigbuf: (unsigned char *)sig.data(), siglen: (unsigned int)sig.size(), pkey) != 1) { |
1528 | state = VerifyError; |
1529 | return false; |
1530 | } |
1531 | } |
1532 | state = Idle; |
1533 | return true; |
1534 | } else |
1535 | return false; |
1536 | } |
1537 | }; |
1538 | |
1539 | //---------------------------------------------------------------------------- |
1540 | // MyDLGroup |
1541 | //---------------------------------------------------------------------------- |
1542 | |
1543 | // IETF primes from Botan |
1544 | static const char *IETF_1024_PRIME = |
1545 | "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" |
1546 | "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" |
1547 | "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" |
1548 | "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" |
1549 | "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381" |
1550 | "FFFFFFFF FFFFFFFF" ; |
1551 | |
1552 | static const char *IETF_2048_PRIME = |
1553 | "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" |
1554 | "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" |
1555 | "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" |
1556 | "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" |
1557 | "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" |
1558 | "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" |
1559 | "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" |
1560 | "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" |
1561 | "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" |
1562 | "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" |
1563 | "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF" ; |
1564 | |
1565 | static const char *IETF_4096_PRIME = |
1566 | "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" |
1567 | "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" |
1568 | "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" |
1569 | "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" |
1570 | "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" |
1571 | "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" |
1572 | "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" |
1573 | "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" |
1574 | "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" |
1575 | "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" |
1576 | "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" |
1577 | "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" |
1578 | "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" |
1579 | "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" |
1580 | "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" |
1581 | "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" |
1582 | "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" |
1583 | "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" |
1584 | "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" |
1585 | "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" |
1586 | "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" |
1587 | "FFFFFFFF FFFFFFFF" ; |
1588 | |
1589 | #ifndef OPENSSL_FIPS |
1590 | // JCE seeds from Botan |
1591 | static const char *JCE_512_SEED = "B869C82B 35D70E1B 1FF91B28 E37A62EC DC34409B" ; |
1592 | static const int JCE_512_COUNTER = 123; |
1593 | |
1594 | static const char *JCE_768_SEED = "77D0F8C4 DAD15EB8 C4F2F8D6 726CEFD9 6D5BB399" ; |
1595 | static const int JCE_768_COUNTER = 263; |
1596 | |
1597 | static const char *JCE_1024_SEED = "8D515589 4229D5E6 89EE01E6 018A237E 2CAE64CD" ; |
1598 | static const int JCE_1024_COUNTER = 92; |
1599 | #endif |
1600 | |
1601 | static QByteArray dehex(const QByteArray &hex) |
1602 | { |
1603 | QString str; |
1604 | for (const char c : hex) { |
1605 | if (c != ' ') |
1606 | str += QLatin1Char(c); |
1607 | } |
1608 | return hexToArray(hexString: str); |
1609 | } |
1610 | |
1611 | static BigInteger decode(const QByteArray &prime) |
1612 | { |
1613 | QByteArray a(1, 0); // 1 byte of zero padding |
1614 | a.append(a: dehex(hex: prime)); |
1615 | return BigInteger(SecureArray(a)); |
1616 | } |
1617 | |
1618 | #ifndef OPENSSL_FIPS |
1619 | static QByteArray decode_seed(const QByteArray &hex_seed) |
1620 | { |
1621 | return dehex(hex: hex_seed); |
1622 | } |
1623 | #endif |
1624 | |
1625 | class DLParams |
1626 | { |
1627 | public: |
1628 | BigInteger p, q, g; |
1629 | }; |
1630 | |
1631 | #ifndef OPENSSL_FIPS |
1632 | |
1633 | static bool make_dlgroup(const QByteArray &seed, int bits, int counter, DLParams *params) |
1634 | { |
1635 | int ret_counter; |
1636 | std::unique_ptr<DSA, DsaDeleter> dsa(DSA_new()); |
1637 | if (!dsa) |
1638 | return false; |
1639 | |
1640 | if (DSA_generate_parameters_ex( |
1641 | dsa: dsa.get(), bits, seed: (const unsigned char *)seed.data(), seed_len: seed.size(), counter_ret: &ret_counter, h_ret: nullptr, cb: nullptr) != 1) |
1642 | return false; |
1643 | |
1644 | if (ret_counter != counter) |
1645 | return false; |
1646 | |
1647 | const BIGNUM *bnp, *bnq, *bng; |
1648 | DSA_get0_pqg(d: dsa.get(), p: &bnp, q: &bnq, g: &bng); |
1649 | params->p = bn2bi(n: bnp); |
1650 | params->q = bn2bi(n: bnq); |
1651 | params->g = bn2bi(n: bng); |
1652 | |
1653 | return true; |
1654 | } |
1655 | #endif |
1656 | |
1657 | static bool get_dlgroup(const BigInteger &p, const BigInteger &g, DLParams *params) |
1658 | { |
1659 | params->p = p; |
1660 | params->q = BigInteger(0); |
1661 | params->g = g; |
1662 | return true; |
1663 | } |
1664 | |
1665 | class DLGroupMaker : public QThread |
1666 | { |
1667 | Q_OBJECT |
1668 | public: |
1669 | DLGroupSet set; |
1670 | bool ok; |
1671 | DLParams params; |
1672 | |
1673 | DLGroupMaker(DLGroupSet _set) |
1674 | { |
1675 | set = _set; |
1676 | } |
1677 | |
1678 | ~DLGroupMaker() override |
1679 | { |
1680 | wait(); |
1681 | } |
1682 | |
1683 | void run() override |
1684 | { |
1685 | switch (set) { |
1686 | #ifndef OPENSSL_FIPS |
1687 | case DSA_512: |
1688 | ok = make_dlgroup(seed: decode_seed(hex_seed: JCE_512_SEED), bits: 512, counter: JCE_512_COUNTER, params: ¶ms); |
1689 | break; |
1690 | |
1691 | case DSA_768: |
1692 | ok = make_dlgroup(seed: decode_seed(hex_seed: JCE_768_SEED), bits: 768, counter: JCE_768_COUNTER, params: ¶ms); |
1693 | break; |
1694 | |
1695 | case DSA_1024: |
1696 | ok = make_dlgroup(seed: decode_seed(hex_seed: JCE_1024_SEED), bits: 1024, counter: JCE_1024_COUNTER, params: ¶ms); |
1697 | break; |
1698 | #endif |
1699 | |
1700 | case IETF_1024: |
1701 | ok = get_dlgroup(p: decode(prime: IETF_1024_PRIME), g: 2, params: ¶ms); |
1702 | break; |
1703 | |
1704 | case IETF_2048: |
1705 | ok = get_dlgroup(p: decode(prime: IETF_2048_PRIME), g: 2, params: ¶ms); |
1706 | break; |
1707 | |
1708 | case IETF_4096: |
1709 | ok = get_dlgroup(p: decode(prime: IETF_4096_PRIME), g: 2, params: ¶ms); |
1710 | break; |
1711 | |
1712 | default: |
1713 | ok = false; |
1714 | break; |
1715 | } |
1716 | } |
1717 | }; |
1718 | |
1719 | class MyDLGroup : public DLGroupContext |
1720 | { |
1721 | Q_OBJECT |
1722 | public: |
1723 | DLGroupMaker *gm; |
1724 | bool wasBlocking; |
1725 | DLParams params; |
1726 | bool empty; |
1727 | |
1728 | MyDLGroup(Provider *p) |
1729 | : DLGroupContext(p) |
1730 | { |
1731 | gm = nullptr; |
1732 | empty = true; |
1733 | } |
1734 | |
1735 | MyDLGroup(const MyDLGroup &from) |
1736 | : DLGroupContext(from.provider()) |
1737 | { |
1738 | gm = nullptr; |
1739 | empty = true; |
1740 | } |
1741 | |
1742 | ~MyDLGroup() override |
1743 | { |
1744 | delete gm; |
1745 | } |
1746 | |
1747 | Provider::Context *clone() const override |
1748 | { |
1749 | return new MyDLGroup(*this); |
1750 | } |
1751 | |
1752 | QList<DLGroupSet> supportedGroupSets() const override |
1753 | { |
1754 | QList<DLGroupSet> list; |
1755 | |
1756 | // DSA_* was removed in FIPS specification |
1757 | // https://bugzilla.redhat.com/show_bug.cgi?id=1144655 |
1758 | #ifndef OPENSSL_FIPS |
1759 | list += DSA_512; |
1760 | list += DSA_768; |
1761 | list += DSA_1024; |
1762 | #endif |
1763 | list += IETF_1024; |
1764 | list += IETF_2048; |
1765 | list += IETF_4096; |
1766 | return list; |
1767 | } |
1768 | |
1769 | bool isNull() const override |
1770 | { |
1771 | return empty; |
1772 | } |
1773 | |
1774 | void fetchGroup(DLGroupSet set, bool block) override |
1775 | { |
1776 | params = DLParams(); |
1777 | empty = true; |
1778 | |
1779 | gm = new DLGroupMaker(set); |
1780 | wasBlocking = block; |
1781 | if (block) { |
1782 | gm->run(); |
1783 | gm_finished(); |
1784 | } else { |
1785 | connect(sender: gm, signal: &DLGroupMaker::finished, context: this, slot: &MyDLGroup::gm_finished); |
1786 | gm->start(); |
1787 | } |
1788 | } |
1789 | |
1790 | void getResult(BigInteger *p, BigInteger *q, BigInteger *g) const override |
1791 | { |
1792 | *p = params.p; |
1793 | *q = params.q; |
1794 | *g = params.g; |
1795 | } |
1796 | |
1797 | private Q_SLOTS: |
1798 | void gm_finished() |
1799 | { |
1800 | bool ok = gm->ok; |
1801 | if (ok) { |
1802 | params = gm->params; |
1803 | empty = false; |
1804 | } |
1805 | |
1806 | if (wasBlocking) |
1807 | delete gm; |
1808 | else |
1809 | gm->deleteLater(); |
1810 | gm = nullptr; |
1811 | |
1812 | if (!wasBlocking) |
1813 | emit finished(); |
1814 | } |
1815 | }; |
1816 | |
1817 | //---------------------------------------------------------------------------- |
1818 | // RSAKey |
1819 | //---------------------------------------------------------------------------- |
1820 | namespace { |
1821 | static const auto RsaDeleter = [](RSA *pointer) { |
1822 | if (pointer) |
1823 | RSA_free(r: (RSA *)pointer); |
1824 | }; |
1825 | |
1826 | static const auto BnDeleter = [](BIGNUM *pointer) { |
1827 | if (pointer) |
1828 | BN_free(a: (BIGNUM *)pointer); |
1829 | }; |
1830 | } // end of anonymous namespace |
1831 | |
1832 | class RSAKeyMaker : public QThread |
1833 | { |
1834 | Q_OBJECT |
1835 | public: |
1836 | RSA *result; |
1837 | int bits, exp; |
1838 | |
1839 | RSAKeyMaker(int _bits, int _exp, QObject *parent = nullptr) |
1840 | : QThread(parent) |
1841 | , result(nullptr) |
1842 | , bits(_bits) |
1843 | , exp(_exp) |
1844 | { |
1845 | } |
1846 | |
1847 | ~RSAKeyMaker() override |
1848 | { |
1849 | wait(); |
1850 | if (result) |
1851 | RSA_free(r: result); |
1852 | } |
1853 | |
1854 | void run() override |
1855 | { |
1856 | std::unique_ptr<RSA, decltype(RsaDeleter)> rsa(RSA_new(), RsaDeleter); |
1857 | if (!rsa) |
1858 | return; |
1859 | |
1860 | std::unique_ptr<BIGNUM, decltype(BnDeleter)> e(BN_new(), BnDeleter); |
1861 | if (!e) |
1862 | return; |
1863 | |
1864 | BN_clear(a: e.get()); |
1865 | if (BN_set_word(a: e.get(), w: exp) != 1) |
1866 | return; |
1867 | |
1868 | if (RSA_generate_key_ex(rsa: rsa.get(), bits, e: e.get(), cb: nullptr) == 0) { |
1869 | return; |
1870 | } |
1871 | |
1872 | result = rsa.release(); |
1873 | } |
1874 | |
1875 | RSA *takeResult() |
1876 | { |
1877 | RSA *rsa = result; |
1878 | result = nullptr; |
1879 | return rsa; |
1880 | } |
1881 | }; |
1882 | |
1883 | class RSAKey : public RSAContext |
1884 | { |
1885 | Q_OBJECT |
1886 | public: |
1887 | EVPKey evp; |
1888 | RSAKeyMaker *keymaker; |
1889 | bool wasBlocking; |
1890 | bool sec; |
1891 | |
1892 | RSAKey(Provider *p) |
1893 | : RSAContext(p) |
1894 | { |
1895 | keymaker = nullptr; |
1896 | sec = false; |
1897 | } |
1898 | |
1899 | RSAKey(const RSAKey &from) |
1900 | : RSAContext(from.provider()) |
1901 | , evp(from.evp) |
1902 | { |
1903 | keymaker = nullptr; |
1904 | sec = from.sec; |
1905 | } |
1906 | |
1907 | ~RSAKey() override |
1908 | { |
1909 | delete keymaker; |
1910 | } |
1911 | |
1912 | Provider::Context *clone() const override |
1913 | { |
1914 | return new RSAKey(*this); |
1915 | } |
1916 | |
1917 | bool isNull() const override |
1918 | { |
1919 | return (evp.pkey ? false : true); |
1920 | } |
1921 | |
1922 | PKey::Type type() const override |
1923 | { |
1924 | return PKey::RSA; |
1925 | } |
1926 | |
1927 | bool isPrivate() const override |
1928 | { |
1929 | return sec; |
1930 | } |
1931 | |
1932 | bool canExport() const override |
1933 | { |
1934 | return true; |
1935 | } |
1936 | |
1937 | void convertToPublic() override |
1938 | { |
1939 | if (!sec) |
1940 | return; |
1941 | |
1942 | // extract the public key into DER format |
1943 | const RSA *rsa_pkey = EVP_PKEY_get0_RSA(pkey: evp.pkey); |
1944 | int len = i2d_RSAPublicKey(a: rsa_pkey, out: nullptr); |
1945 | SecureArray result(len); |
1946 | unsigned char *p = (unsigned char *)result.data(); |
1947 | i2d_RSAPublicKey(a: rsa_pkey, out: &p); |
1948 | p = (unsigned char *)result.data(); |
1949 | |
1950 | // put the DER public key back into openssl |
1951 | evp.reset(); |
1952 | RSA *rsa = d2i_RSAPublicKey(a: nullptr, in: (const unsigned char **)&p, len: result.size()); |
1953 | evp.pkey = EVP_PKEY_new(); |
1954 | EVP_PKEY_assign_RSA(evp.pkey, rsa); |
1955 | sec = false; |
1956 | } |
1957 | |
1958 | int bits() const override |
1959 | { |
1960 | return EVP_PKEY_bits(pkey: evp.pkey); |
1961 | } |
1962 | |
1963 | int maximumEncryptSize(EncryptionAlgorithm alg) const override |
1964 | { |
1965 | const RSA *rsa = EVP_PKEY_get0_RSA(pkey: evp.pkey); |
1966 | int size = 0; |
1967 | switch (alg) { |
1968 | case EME_PKCS1v15: |
1969 | size = RSA_size(rsa) - 11 - 1; |
1970 | break; |
1971 | case EME_PKCS1_OAEP: |
1972 | size = RSA_size(rsa) - 41 - 1; |
1973 | break; |
1974 | case EME_PKCS1v15_SSL: |
1975 | size = RSA_size(rsa) - 11 - 1; |
1976 | break; |
1977 | case EME_NO_PADDING: |
1978 | size = RSA_size(rsa) - 1; |
1979 | break; |
1980 | } |
1981 | |
1982 | return size; |
1983 | } |
1984 | |
1985 | SecureArray encrypt(const SecureArray &in, EncryptionAlgorithm alg) override |
1986 | { |
1987 | const RSA *rsa = EVP_PKEY_get0_RSA(pkey: evp.pkey); |
1988 | SecureArray buf = in; |
1989 | int max = maximumEncryptSize(alg); |
1990 | |
1991 | if (buf.size() > max) |
1992 | buf.resize(size: max); |
1993 | SecureArray result(RSA_size(rsa)); |
1994 | |
1995 | int pad; |
1996 | switch (alg) { |
1997 | case EME_PKCS1v15: |
1998 | pad = RSA_PKCS1_PADDING; |
1999 | break; |
2000 | case EME_PKCS1_OAEP: |
2001 | pad = RSA_PKCS1_OAEP_PADDING; |
2002 | break; |
2003 | // OPENSSL_VERSION_MAJOR is only defined on openssl > 3.0 |
2004 | // that doesn't have RSA_SSLV23_PADDING so we can use it negatively here |
2005 | #ifndef OPENSSL_VERSION_MAJOR |
2006 | case EME_PKCS1v15_SSL: |
2007 | pad = RSA_SSLV23_PADDING; |
2008 | break; |
2009 | #endif |
2010 | case EME_NO_PADDING: |
2011 | pad = RSA_NO_PADDING; |
2012 | break; |
2013 | default: |
2014 | return SecureArray(); |
2015 | break; |
2016 | } |
2017 | |
2018 | int ret; |
2019 | if (isPrivate()) |
2020 | ret = RSA_private_encrypt( |
2021 | flen: buf.size(), from: (unsigned char *)buf.data(), to: (unsigned char *)result.data(), rsa: (RSA *)rsa, padding: pad); |
2022 | else |
2023 | ret = RSA_public_encrypt( |
2024 | flen: buf.size(), from: (unsigned char *)buf.data(), to: (unsigned char *)result.data(), rsa: (RSA *)rsa, padding: pad); |
2025 | |
2026 | if (ret < 0) |
2027 | return SecureArray(); |
2028 | result.resize(size: ret); |
2029 | |
2030 | return result; |
2031 | } |
2032 | |
2033 | bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg) override |
2034 | { |
2035 | const RSA *rsa = EVP_PKEY_get0_RSA(pkey: evp.pkey); |
2036 | SecureArray result(RSA_size(rsa)); |
2037 | int pad; |
2038 | |
2039 | switch (alg) { |
2040 | case EME_PKCS1v15: |
2041 | pad = RSA_PKCS1_PADDING; |
2042 | break; |
2043 | case EME_PKCS1_OAEP: |
2044 | pad = RSA_PKCS1_OAEP_PADDING; |
2045 | break; |
2046 | // OPENSSL_VERSION_MAJOR is only defined on openssl > 3.0 |
2047 | // that doesn't have RSA_SSLV23_PADDING so we can use it negatively here |
2048 | #ifndef OPENSSL_VERSION_MAJOR |
2049 | case EME_PKCS1v15_SSL: |
2050 | pad = RSA_SSLV23_PADDING; |
2051 | break; |
2052 | #endif |
2053 | case EME_NO_PADDING: |
2054 | pad = RSA_NO_PADDING; |
2055 | break; |
2056 | default: |
2057 | return false; |
2058 | break; |
2059 | } |
2060 | |
2061 | int ret; |
2062 | if (isPrivate()) |
2063 | ret = RSA_private_decrypt( |
2064 | flen: in.size(), from: (unsigned char *)in.data(), to: (unsigned char *)result.data(), rsa: (RSA *)rsa, padding: pad); |
2065 | else |
2066 | ret = RSA_public_decrypt( |
2067 | flen: in.size(), from: (unsigned char *)in.data(), to: (unsigned char *)result.data(), rsa: (RSA *)rsa, padding: pad); |
2068 | |
2069 | if (ret < 0) |
2070 | return false; |
2071 | result.resize(size: ret); |
2072 | |
2073 | *out = result; |
2074 | return true; |
2075 | } |
2076 | |
2077 | void startSign(SignatureAlgorithm alg, SignatureFormat) override |
2078 | { |
2079 | const EVP_MD *md = nullptr; |
2080 | if (alg == EMSA3_SHA1) |
2081 | md = EVP_sha1(); |
2082 | else if (alg == EMSA3_MD5) |
2083 | md = EVP_md5(); |
2084 | else if (alg == EMSA3_SHA224) |
2085 | md = EVP_sha224(); |
2086 | else if (alg == EMSA3_SHA256) |
2087 | md = EVP_sha256(); |
2088 | else if (alg == EMSA3_SHA384) |
2089 | md = EVP_sha384(); |
2090 | else if (alg == EMSA3_SHA512) |
2091 | md = EVP_sha512(); |
2092 | else if (alg == EMSA3_Raw) { |
2093 | // md = 0 |
2094 | } else if (s_legacyProviderAvailable) { |
2095 | if (alg == EMSA3_RIPEMD160) |
2096 | md = EVP_ripemd160(); |
2097 | #ifdef HAVE_OPENSSL_MD2 |
2098 | else if (alg == EMSA3_MD2) |
2099 | md = EVP_md2(); |
2100 | #endif |
2101 | } |
2102 | |
2103 | evp.startSign(type: md); |
2104 | } |
2105 | |
2106 | void startVerify(SignatureAlgorithm alg, SignatureFormat) override |
2107 | { |
2108 | const EVP_MD *md = nullptr; |
2109 | if (alg == EMSA3_SHA1) |
2110 | md = EVP_sha1(); |
2111 | else if (alg == EMSA3_MD5) |
2112 | md = EVP_md5(); |
2113 | else if (alg == EMSA3_SHA224) |
2114 | md = EVP_sha224(); |
2115 | else if (alg == EMSA3_SHA256) |
2116 | md = EVP_sha256(); |
2117 | else if (alg == EMSA3_SHA384) |
2118 | md = EVP_sha384(); |
2119 | else if (alg == EMSA3_SHA512) |
2120 | md = EVP_sha512(); |
2121 | else if (alg == EMSA3_Raw) { |
2122 | // md = 0 |
2123 | } else if (s_legacyProviderAvailable) { |
2124 | if (alg == EMSA3_RIPEMD160) |
2125 | md = EVP_ripemd160(); |
2126 | #ifdef HAVE_OPENSSL_MD2 |
2127 | else if (alg == EMSA3_MD2) |
2128 | md = EVP_md2(); |
2129 | #endif |
2130 | } |
2131 | evp.startVerify(type: md); |
2132 | } |
2133 | |
2134 | void update(const MemoryRegion &in) override |
2135 | { |
2136 | evp.update(in); |
2137 | } |
2138 | |
2139 | QByteArray endSign() override |
2140 | { |
2141 | return evp.endSign().toByteArray(); |
2142 | } |
2143 | |
2144 | bool endVerify(const QByteArray &sig) override |
2145 | { |
2146 | return evp.endVerify(sig); |
2147 | } |
2148 | |
2149 | void createPrivate(int bits, int exp, bool block) override |
2150 | { |
2151 | evp.reset(); |
2152 | |
2153 | keymaker = new RSAKeyMaker(bits, exp, !block ? this : nullptr); |
2154 | wasBlocking = block; |
2155 | if (block) { |
2156 | keymaker->run(); |
2157 | km_finished(); |
2158 | } else { |
2159 | connect(sender: keymaker, signal: &RSAKeyMaker::finished, context: this, slot: &RSAKey::km_finished); |
2160 | keymaker->start(); |
2161 | } |
2162 | } |
2163 | |
2164 | void createPrivate(const BigInteger &n, |
2165 | const BigInteger &e, |
2166 | const BigInteger &p, |
2167 | const BigInteger &q, |
2168 | const BigInteger &d) override |
2169 | { |
2170 | evp.reset(); |
2171 | |
2172 | RSA *rsa = RSA_new(); |
2173 | if (RSA_set0_key(r: rsa, n: bi2bn(n), e: bi2bn(n: e), d: bi2bn(n: d)) == 0 || RSA_set0_factors(r: rsa, p: bi2bn(n: p), q: bi2bn(n: q)) == 0) { |
2174 | // Free BIGNUMS? |
2175 | RSA_free(r: rsa); |
2176 | return; |
2177 | } |
2178 | |
2179 | // When private key has no Public Exponent (e) or Private Exponent (d) |
2180 | // need to disable blinding. Otherwise decryption will be broken. |
2181 | // http://www.mail-archive.com/openssl-users@openssl.org/msg63530.html |
2182 | if (e == BigInteger(0) || d == BigInteger(0)) |
2183 | RSA_blinding_off(rsa); |
2184 | |
2185 | evp.pkey = EVP_PKEY_new(); |
2186 | EVP_PKEY_assign_RSA(evp.pkey, rsa); |
2187 | sec = true; |
2188 | } |
2189 | |
2190 | void createPublic(const BigInteger &n, const BigInteger &e) override |
2191 | { |
2192 | evp.reset(); |
2193 | |
2194 | RSA *rsa = RSA_new(); |
2195 | if (RSA_set0_key(r: rsa, n: bi2bn(n), e: bi2bn(n: e), d: nullptr) == 0) { |
2196 | RSA_free(r: rsa); |
2197 | return; |
2198 | } |
2199 | |
2200 | evp.pkey = EVP_PKEY_new(); |
2201 | EVP_PKEY_assign_RSA(evp.pkey, rsa); |
2202 | sec = false; |
2203 | } |
2204 | |
2205 | BigInteger n() const override |
2206 | { |
2207 | const RSA *rsa = EVP_PKEY_get0_RSA(pkey: evp.pkey); |
2208 | const BIGNUM *bnn; |
2209 | RSA_get0_key(r: rsa, n: &bnn, e: nullptr, d: nullptr); |
2210 | return bn2bi(n: bnn); |
2211 | } |
2212 | |
2213 | BigInteger e() const override |
2214 | { |
2215 | const RSA *rsa = EVP_PKEY_get0_RSA(pkey: evp.pkey); |
2216 | const BIGNUM *bne; |
2217 | RSA_get0_key(r: rsa, n: nullptr, e: &bne, d: nullptr); |
2218 | return bn2bi(n: bne); |
2219 | } |
2220 | |
2221 | BigInteger p() const override |
2222 | { |
2223 | const RSA *rsa = EVP_PKEY_get0_RSA(pkey: evp.pkey); |
2224 | const BIGNUM *bnp; |
2225 | RSA_get0_factors(r: rsa, p: &bnp, q: nullptr); |
2226 | return bn2bi(n: bnp); |
2227 | } |
2228 | |
2229 | BigInteger q() const override |
2230 | { |
2231 | const RSA *rsa = EVP_PKEY_get0_RSA(pkey: evp.pkey); |
2232 | const BIGNUM *bnq; |
2233 | RSA_get0_factors(r: rsa, p: nullptr, q: &bnq); |
2234 | return bn2bi(n: bnq); |
2235 | } |
2236 | |
2237 | BigInteger d() const override |
2238 | { |
2239 | const RSA *rsa = EVP_PKEY_get0_RSA(pkey: evp.pkey); |
2240 | const BIGNUM *bnd; |
2241 | RSA_get0_key(r: rsa, n: nullptr, e: nullptr, d: &bnd); |
2242 | return bn2bi(n: bnd); |
2243 | } |
2244 | |
2245 | private Q_SLOTS: |
2246 | void km_finished() |
2247 | { |
2248 | RSA *rsa = keymaker->takeResult(); |
2249 | if (wasBlocking) |
2250 | delete keymaker; |
2251 | else |
2252 | keymaker->deleteLater(); |
2253 | keymaker = nullptr; |
2254 | |
2255 | if (rsa) { |
2256 | evp.pkey = EVP_PKEY_new(); |
2257 | EVP_PKEY_assign_RSA(evp.pkey, rsa); |
2258 | sec = true; |
2259 | } |
2260 | |
2261 | if (!wasBlocking) |
2262 | emit finished(); |
2263 | } |
2264 | }; |
2265 | |
2266 | //---------------------------------------------------------------------------- |
2267 | // DSAKey |
2268 | //---------------------------------------------------------------------------- |
2269 | class DSAKeyMaker : public QThread |
2270 | { |
2271 | Q_OBJECT |
2272 | public: |
2273 | DLGroup domain; |
2274 | DSA *result; |
2275 | |
2276 | DSAKeyMaker(const DLGroup &_domain, QObject *parent = nullptr) |
2277 | : QThread(parent) |
2278 | , domain(_domain) |
2279 | , result(nullptr) |
2280 | { |
2281 | } |
2282 | |
2283 | ~DSAKeyMaker() override |
2284 | { |
2285 | wait(); |
2286 | if (result) |
2287 | DSA_free(r: result); |
2288 | } |
2289 | |
2290 | void run() override |
2291 | { |
2292 | std::unique_ptr<DSA, DsaDeleter> dsa(DSA_new()); |
2293 | BIGNUM *pne = bi2bn(n: domain.p()), *qne = bi2bn(n: domain.q()), *gne = bi2bn(n: domain.g()); |
2294 | |
2295 | if (!DSA_set0_pqg(d: dsa.get(), p: pne, q: qne, g: gne)) { |
2296 | return; |
2297 | } |
2298 | if (!DSA_generate_key(a: dsa.get())) { |
2299 | // OPENSSL_VERSION_MAJOR is only defined in openssl3 |
2300 | #ifdef OPENSSL_VERSION_MAJOR |
2301 | // HACK |
2302 | // in openssl3 there is an internal flag for "legacy" values |
2303 | // bits < 2048 && seed_len <= 20 |
2304 | // set in ossl_ffc_params_FIPS186_2_generate (called by DSA_generate_parameters_ex) |
2305 | // that we have no way to get or set, so if the bits are smaller than 2048 we generate |
2306 | // a dsa from a dummy seed and then override the p/q/g with the ones we want |
2307 | // so we can reuse the internal flag |
2308 | if (BN_num_bits(a: pne) < 2048) { |
2309 | int dummy; |
2310 | dsa.reset(p: DSA_new()); |
2311 | if (DSA_generate_parameters_ex( |
2312 | dsa: dsa.get(), bits: 512, seed: (const unsigned char *)"THIS_IS_A_DUMMY_SEED" , seed_len: 20, counter_ret: &dummy, h_ret: nullptr, cb: nullptr) != |
2313 | 1) { |
2314 | return; |
2315 | } |
2316 | pne = bi2bn(n: domain.p()); |
2317 | qne = bi2bn(n: domain.q()); |
2318 | gne = bi2bn(n: domain.g()); |
2319 | if (!DSA_set0_pqg(d: dsa.get(), p: pne, q: qne, g: gne)) { |
2320 | return; |
2321 | } |
2322 | if (!DSA_generate_key(a: dsa.get())) { |
2323 | return; |
2324 | } |
2325 | } else { |
2326 | return; |
2327 | } |
2328 | #else |
2329 | return; |
2330 | #endif |
2331 | } |
2332 | result = dsa.release(); |
2333 | } |
2334 | |
2335 | DSA *takeResult() |
2336 | { |
2337 | DSA *dsa = result; |
2338 | result = nullptr; |
2339 | return dsa; |
2340 | } |
2341 | }; |
2342 | |
2343 | // note: DSA doesn't use SignatureAlgorithm, since EMSA1 is always assumed |
2344 | class DSAKey : public DSAContext |
2345 | { |
2346 | Q_OBJECT |
2347 | public: |
2348 | EVPKey evp; |
2349 | DSAKeyMaker *keymaker; |
2350 | bool wasBlocking; |
2351 | bool transformsig; |
2352 | bool sec; |
2353 | |
2354 | DSAKey(Provider *p) |
2355 | : DSAContext(p) |
2356 | { |
2357 | keymaker = nullptr; |
2358 | sec = false; |
2359 | } |
2360 | |
2361 | DSAKey(const DSAKey &from) |
2362 | : DSAContext(from.provider()) |
2363 | , evp(from.evp) |
2364 | { |
2365 | keymaker = nullptr; |
2366 | sec = from.sec; |
2367 | } |
2368 | |
2369 | ~DSAKey() override |
2370 | { |
2371 | delete keymaker; |
2372 | } |
2373 | |
2374 | Provider::Context *clone() const override |
2375 | { |
2376 | return new DSAKey(*this); |
2377 | } |
2378 | |
2379 | bool isNull() const override |
2380 | { |
2381 | return (evp.pkey ? false : true); |
2382 | } |
2383 | |
2384 | PKey::Type type() const override |
2385 | { |
2386 | return PKey::DSA; |
2387 | } |
2388 | |
2389 | bool isPrivate() const override |
2390 | { |
2391 | return sec; |
2392 | } |
2393 | |
2394 | bool canExport() const override |
2395 | { |
2396 | return true; |
2397 | } |
2398 | |
2399 | void convertToPublic() override |
2400 | { |
2401 | if (!sec) |
2402 | return; |
2403 | |
2404 | // extract the public key into DER format |
2405 | const DSA *dsa_pkey = EVP_PKEY_get0_DSA(pkey: evp.pkey); |
2406 | int len = i2d_DSAPublicKey(a: dsa_pkey, out: nullptr); |
2407 | SecureArray result(len); |
2408 | unsigned char *p = (unsigned char *)result.data(); |
2409 | i2d_DSAPublicKey(a: dsa_pkey, out: &p); |
2410 | p = (unsigned char *)result.data(); |
2411 | |
2412 | // put the DER public key back into openssl |
2413 | evp.reset(); |
2414 | DSA *dsa = d2i_DSAPublicKey(a: nullptr, in: (const unsigned char **)&p, len: result.size()); |
2415 | evp.pkey = EVP_PKEY_new(); |
2416 | EVP_PKEY_assign_DSA(evp.pkey, dsa); |
2417 | sec = false; |
2418 | } |
2419 | |
2420 | int bits() const override |
2421 | { |
2422 | return EVP_PKEY_bits(pkey: evp.pkey); |
2423 | } |
2424 | |
2425 | void startSign(SignatureAlgorithm, SignatureFormat format) override |
2426 | { |
2427 | // openssl native format is DER, so transform otherwise |
2428 | if (format != DERSequence) |
2429 | transformsig = true; |
2430 | else |
2431 | transformsig = false; |
2432 | |
2433 | evp.startSign(type: EVP_sha1()); |
2434 | } |
2435 | |
2436 | void startVerify(SignatureAlgorithm, SignatureFormat format) override |
2437 | { |
2438 | // openssl native format is DER, so transform otherwise |
2439 | if (format != DERSequence) |
2440 | transformsig = true; |
2441 | else |
2442 | transformsig = false; |
2443 | |
2444 | evp.startVerify(type: EVP_sha1()); |
2445 | } |
2446 | |
2447 | void update(const MemoryRegion &in) override |
2448 | { |
2449 | evp.update(in); |
2450 | } |
2451 | |
2452 | QByteArray endSign() override |
2453 | { |
2454 | SecureArray out = evp.endSign(); |
2455 | if (transformsig) |
2456 | return dsasig_der_to_raw(in: out).toByteArray(); |
2457 | else |
2458 | return out.toByteArray(); |
2459 | } |
2460 | |
2461 | bool endVerify(const QByteArray &sig) override |
2462 | { |
2463 | SecureArray in; |
2464 | if (transformsig) |
2465 | in = dsasig_raw_to_der(in: sig); |
2466 | else |
2467 | in = sig; |
2468 | return evp.endVerify(sig: in); |
2469 | } |
2470 | |
2471 | void createPrivate(const DLGroup &domain, bool block) override |
2472 | { |
2473 | evp.reset(); |
2474 | |
2475 | keymaker = new DSAKeyMaker(domain, !block ? this : nullptr); |
2476 | wasBlocking = block; |
2477 | if (block) { |
2478 | keymaker->run(); |
2479 | km_finished(); |
2480 | } else { |
2481 | connect(sender: keymaker, signal: &DSAKeyMaker::finished, context: this, slot: &DSAKey::km_finished); |
2482 | keymaker->start(); |
2483 | } |
2484 | } |
2485 | |
2486 | void createPrivate(const DLGroup &domain, const BigInteger &y, const BigInteger &x) override |
2487 | { |
2488 | evp.reset(); |
2489 | |
2490 | DSA *dsa = DSA_new(); |
2491 | BIGNUM *bnp = bi2bn(n: domain.p()); |
2492 | BIGNUM *bnq = bi2bn(n: domain.q()); |
2493 | BIGNUM *bng = bi2bn(n: domain.g()); |
2494 | BIGNUM *bnpub_key = bi2bn(n: y); |
2495 | BIGNUM *bnpriv_key = bi2bn(n: x); |
2496 | |
2497 | if (!DSA_set0_pqg(d: dsa, p: bnp, q: bnq, g: bng) || !DSA_set0_key(d: dsa, pub_key: bnpub_key, priv_key: bnpriv_key)) { |
2498 | DSA_free(r: dsa); |
2499 | return; |
2500 | } |
2501 | |
2502 | evp.pkey = EVP_PKEY_new(); |
2503 | EVP_PKEY_assign_DSA(evp.pkey, dsa); |
2504 | sec = true; |
2505 | } |
2506 | |
2507 | void createPublic(const DLGroup &domain, const BigInteger &y) override |
2508 | { |
2509 | evp.reset(); |
2510 | |
2511 | DSA *dsa = DSA_new(); |
2512 | BIGNUM *bnp = bi2bn(n: domain.p()); |
2513 | BIGNUM *bnq = bi2bn(n: domain.q()); |
2514 | BIGNUM *bng = bi2bn(n: domain.g()); |
2515 | BIGNUM *bnpub_key = bi2bn(n: y); |
2516 | |
2517 | if (!DSA_set0_pqg(d: dsa, p: bnp, q: bnq, g: bng) || !DSA_set0_key(d: dsa, pub_key: bnpub_key, priv_key: nullptr)) { |
2518 | DSA_free(r: dsa); |
2519 | return; |
2520 | } |
2521 | |
2522 | evp.pkey = EVP_PKEY_new(); |
2523 | EVP_PKEY_assign_DSA(evp.pkey, dsa); |
2524 | sec = false; |
2525 | } |
2526 | |
2527 | DLGroup domain() const override |
2528 | { |
2529 | const DSA *dsa = EVP_PKEY_get0_DSA(pkey: evp.pkey); |
2530 | const BIGNUM *bnp, *bnq, *bng; |
2531 | DSA_get0_pqg(d: dsa, p: &bnp, q: &bnq, g: &bng); |
2532 | return DLGroup(bn2bi(n: bnp), bn2bi(n: bnq), bn2bi(n: bng)); |
2533 | } |
2534 | |
2535 | BigInteger y() const override |
2536 | { |
2537 | const DSA *dsa = EVP_PKEY_get0_DSA(pkey: evp.pkey); |
2538 | const BIGNUM *bnpub_key; |
2539 | DSA_get0_key(d: dsa, pub_key: &bnpub_key, priv_key: nullptr); |
2540 | return bn2bi(n: bnpub_key); |
2541 | } |
2542 | |
2543 | BigInteger x() const override |
2544 | { |
2545 | const DSA *dsa = EVP_PKEY_get0_DSA(pkey: evp.pkey); |
2546 | const BIGNUM *bnpriv_key; |
2547 | DSA_get0_key(d: dsa, pub_key: nullptr, priv_key: &bnpriv_key); |
2548 | return bn2bi(n: bnpriv_key); |
2549 | } |
2550 | |
2551 | private Q_SLOTS: |
2552 | void km_finished() |
2553 | { |
2554 | DSA *dsa = keymaker->takeResult(); |
2555 | if (wasBlocking) |
2556 | delete keymaker; |
2557 | else |
2558 | keymaker->deleteLater(); |
2559 | keymaker = nullptr; |
2560 | |
2561 | if (dsa) { |
2562 | evp.pkey = EVP_PKEY_new(); |
2563 | EVP_PKEY_assign_DSA(evp.pkey, dsa); |
2564 | sec = true; |
2565 | } |
2566 | |
2567 | if (!wasBlocking) |
2568 | emit finished(); |
2569 | } |
2570 | }; |
2571 | |
2572 | //---------------------------------------------------------------------------- |
2573 | // DHKey |
2574 | //---------------------------------------------------------------------------- |
2575 | class DHKeyMaker : public QThread |
2576 | { |
2577 | Q_OBJECT |
2578 | public: |
2579 | DLGroup domain; |
2580 | DH *result; |
2581 | |
2582 | DHKeyMaker(const DLGroup &_domain, QObject *parent = nullptr) |
2583 | : QThread(parent) |
2584 | , domain(_domain) |
2585 | , result(nullptr) |
2586 | { |
2587 | } |
2588 | |
2589 | ~DHKeyMaker() override |
2590 | { |
2591 | wait(); |
2592 | if (result) |
2593 | DH_free(dh: result); |
2594 | } |
2595 | |
2596 | void run() override |
2597 | { |
2598 | DH *dh = DH_new(); |
2599 | BIGNUM *bnp = bi2bn(n: domain.p()); |
2600 | BIGNUM *bng = bi2bn(n: domain.g()); |
2601 | if (!DH_set0_pqg(dh, p: bnp, q: nullptr, g: bng) || !DH_generate_key(dh)) { |
2602 | DH_free(dh); |
2603 | return; |
2604 | } |
2605 | result = dh; |
2606 | } |
2607 | |
2608 | DH *takeResult() |
2609 | { |
2610 | DH *dh = result; |
2611 | result = nullptr; |
2612 | return dh; |
2613 | } |
2614 | }; |
2615 | |
2616 | class DHKey : public DHContext |
2617 | { |
2618 | Q_OBJECT |
2619 | public: |
2620 | EVPKey evp; |
2621 | DHKeyMaker *keymaker; |
2622 | bool wasBlocking; |
2623 | bool sec; |
2624 | |
2625 | DHKey(Provider *p) |
2626 | : DHContext(p) |
2627 | { |
2628 | keymaker = nullptr; |
2629 | sec = false; |
2630 | } |
2631 | |
2632 | DHKey(const DHKey &from) |
2633 | : DHContext(from.provider()) |
2634 | , evp(from.evp) |
2635 | { |
2636 | keymaker = nullptr; |
2637 | sec = from.sec; |
2638 | } |
2639 | |
2640 | ~DHKey() override |
2641 | { |
2642 | delete keymaker; |
2643 | } |
2644 | |
2645 | Provider::Context *clone() const override |
2646 | { |
2647 | return new DHKey(*this); |
2648 | } |
2649 | |
2650 | bool isNull() const override |
2651 | { |
2652 | return (evp.pkey ? false : true); |
2653 | } |
2654 | |
2655 | PKey::Type type() const override |
2656 | { |
2657 | return PKey::DH; |
2658 | } |
2659 | |
2660 | bool isPrivate() const override |
2661 | { |
2662 | return sec; |
2663 | } |
2664 | |
2665 | bool canExport() const override |
2666 | { |
2667 | return true; |
2668 | } |
2669 | |
2670 | void convertToPublic() override |
2671 | { |
2672 | if (!sec) |
2673 | return; |
2674 | |
2675 | const DH *orig = EVP_PKEY_get0_DH(pkey: evp.pkey); |
2676 | DH *dh = DH_new(); |
2677 | const BIGNUM *bnp, *bng, *bnpub_key; |
2678 | DH_get0_pqg(dh: orig, p: &bnp, q: nullptr, g: &bng); |
2679 | DH_get0_key(dh: orig, pub_key: &bnpub_key, priv_key: nullptr); |
2680 | |
2681 | DH_set0_key(dh, pub_key: BN_dup(a: bnpub_key), priv_key: nullptr); |
2682 | DH_set0_pqg(dh, p: BN_dup(a: bnp), q: nullptr, g: BN_dup(a: bng)); |
2683 | |
2684 | evp.reset(); |
2685 | |
2686 | evp.pkey = EVP_PKEY_new(); |
2687 | EVP_PKEY_assign_DH(evp.pkey, dh); |
2688 | sec = false; |
2689 | } |
2690 | |
2691 | int bits() const override |
2692 | { |
2693 | return EVP_PKEY_bits(pkey: evp.pkey); |
2694 | } |
2695 | |
2696 | SymmetricKey deriveKey(const PKeyBase &theirs) override |
2697 | { |
2698 | const DH *dh = EVP_PKEY_get0_DH(pkey: evp.pkey); |
2699 | const DH *them = EVP_PKEY_get0_DH(pkey: static_cast<const DHKey *>(&theirs)->evp.pkey); |
2700 | const BIGNUM *bnpub_key; |
2701 | DH_get0_key(dh: them, pub_key: &bnpub_key, priv_key: nullptr); |
2702 | |
2703 | SecureArray result(DH_size(dh)); |
2704 | int ret = DH_compute_key(key: (unsigned char *)result.data(), pub_key: bnpub_key, dh: (DH *)dh); |
2705 | if (ret <= 0) |
2706 | return SymmetricKey(); |
2707 | result.resize(size: ret); |
2708 | return SymmetricKey(result); |
2709 | } |
2710 | |
2711 | void createPrivate(const DLGroup &domain, bool block) override |
2712 | { |
2713 | evp.reset(); |
2714 | |
2715 | keymaker = new DHKeyMaker(domain, !block ? this : nullptr); |
2716 | wasBlocking = block; |
2717 | if (block) { |
2718 | keymaker->run(); |
2719 | km_finished(); |
2720 | } else { |
2721 | connect(sender: keymaker, signal: &DHKeyMaker::finished, context: this, slot: &DHKey::km_finished); |
2722 | keymaker->start(); |
2723 | } |
2724 | } |
2725 | |
2726 | void createPrivate(const DLGroup &domain, const BigInteger &y, const BigInteger &x) override |
2727 | { |
2728 | evp.reset(); |
2729 | |
2730 | DH *dh = DH_new(); |
2731 | BIGNUM *bnp = bi2bn(n: domain.p()); |
2732 | BIGNUM *bng = bi2bn(n: domain.g()); |
2733 | BIGNUM *bnpub_key = bi2bn(n: y); |
2734 | BIGNUM *bnpriv_key = bi2bn(n: x); |
2735 | |
2736 | if (!DH_set0_key(dh, pub_key: bnpub_key, priv_key: bnpriv_key) || !DH_set0_pqg(dh, p: bnp, q: nullptr, g: bng)) { |
2737 | DH_free(dh); |
2738 | return; |
2739 | } |
2740 | |
2741 | evp.pkey = EVP_PKEY_new(); |
2742 | EVP_PKEY_assign_DH(evp.pkey, dh); |
2743 | sec = true; |
2744 | } |
2745 | |
2746 | void createPublic(const DLGroup &domain, const BigInteger &y) override |
2747 | { |
2748 | evp.reset(); |
2749 | |
2750 | DH *dh = DH_new(); |
2751 | BIGNUM *bnp = bi2bn(n: domain.p()); |
2752 | BIGNUM *bng = bi2bn(n: domain.g()); |
2753 | BIGNUM *bnpub_key = bi2bn(n: y); |
2754 | |
2755 | if (!DH_set0_key(dh, pub_key: bnpub_key, priv_key: nullptr) || !DH_set0_pqg(dh, p: bnp, q: nullptr, g: bng)) { |
2756 | DH_free(dh); |
2757 | return; |
2758 | } |
2759 | |
2760 | evp.pkey = EVP_PKEY_new(); |
2761 | EVP_PKEY_assign_DH(evp.pkey, dh); |
2762 | sec = false; |
2763 | } |
2764 | |
2765 | DLGroup domain() const override |
2766 | { |
2767 | const DH *dh = EVP_PKEY_get0_DH(pkey: evp.pkey); |
2768 | const BIGNUM *bnp, *bng; |
2769 | DH_get0_pqg(dh, p: &bnp, q: nullptr, g: &bng); |
2770 | return DLGroup(bn2bi(n: bnp), bn2bi(n: bng)); |
2771 | } |
2772 | |
2773 | BigInteger y() const override |
2774 | { |
2775 | const DH *dh = EVP_PKEY_get0_DH(pkey: evp.pkey); |
2776 | const BIGNUM *bnpub_key; |
2777 | DH_get0_key(dh, pub_key: &bnpub_key, priv_key: nullptr); |
2778 | return bn2bi(n: bnpub_key); |
2779 | } |
2780 | |
2781 | BigInteger x() const override |
2782 | { |
2783 | const DH *dh = EVP_PKEY_get0_DH(pkey: evp.pkey); |
2784 | const BIGNUM *bnpriv_key; |
2785 | DH_get0_key(dh, pub_key: nullptr, priv_key: &bnpriv_key); |
2786 | return bn2bi(n: bnpriv_key); |
2787 | } |
2788 | |
2789 | private Q_SLOTS: |
2790 | void km_finished() |
2791 | { |
2792 | DH *dh = keymaker->takeResult(); |
2793 | if (wasBlocking) |
2794 | delete keymaker; |
2795 | else |
2796 | keymaker->deleteLater(); |
2797 | keymaker = nullptr; |
2798 | |
2799 | if (dh) { |
2800 | evp.pkey = EVP_PKEY_new(); |
2801 | EVP_PKEY_assign_DH(evp.pkey, dh); |
2802 | sec = true; |
2803 | } |
2804 | |
2805 | if (!wasBlocking) |
2806 | emit finished(); |
2807 | } |
2808 | }; |
2809 | |
2810 | //---------------------------------------------------------------------------- |
2811 | // QCA-based RSA_METHOD |
2812 | //---------------------------------------------------------------------------- |
2813 | |
2814 | // only supports EMSA3_Raw for now |
2815 | class QCA_RSA_METHOD |
2816 | { |
2817 | public: |
2818 | RSAPrivateKey key; |
2819 | |
2820 | QCA_RSA_METHOD(const RSAPrivateKey &_key, RSA *rsa) |
2821 | { |
2822 | key = _key; |
2823 | RSA_set_method(rsa, meth: rsa_method()); |
2824 | RSA_set_app_data(rsa, this); |
2825 | BIGNUM *bnn = bi2bn(n: _key.n()); |
2826 | BIGNUM *bne = bi2bn(n: _key.e()); |
2827 | |
2828 | RSA_set0_key(r: rsa, n: bnn, e: bne, d: nullptr); |
2829 | } |
2830 | |
2831 | RSA_METHOD *rsa_method() |
2832 | { |
2833 | static RSA_METHOD *ops = nullptr; |
2834 | |
2835 | if (!ops) { |
2836 | ops = RSA_meth_dup(meth: RSA_get_default_method()); |
2837 | RSA_meth_set_priv_enc(rsa: ops, priv_enc: nullptr); // pkcs11_rsa_encrypt |
2838 | RSA_meth_set_priv_dec(rsa: ops, priv_dec: rsa_priv_dec); // pkcs11_rsa_encrypt |
2839 | RSA_meth_set_sign(rsa: ops, sign: nullptr); |
2840 | RSA_meth_set_verify(rsa: ops, verify: nullptr); // pkcs11_rsa_verify |
2841 | RSA_meth_set_finish(rsa: ops, finish: rsa_finish); |
2842 | } |
2843 | return ops; |
2844 | } |
2845 | |
2846 | static int rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) |
2847 | { |
2848 | QCA::EncryptionAlgorithm algo; |
2849 | |
2850 | if (padding == RSA_PKCS1_PADDING) { |
2851 | algo = QCA::EME_PKCS1v15; |
2852 | } else if (padding == RSA_PKCS1_OAEP_PADDING) { |
2853 | algo = QCA::EME_PKCS1_OAEP; |
2854 | } else { |
2855 | RSAerr(RSA_F_RSA_OSSL_PRIVATE_DECRYPT, RSA_R_UNKNOWN_PADDING_TYPE); |
2856 | return -1; |
2857 | } |
2858 | |
2859 | QCA_RSA_METHOD *self = (QCA_RSA_METHOD *)RSA_get_app_data(rsa); |
2860 | |
2861 | QCA::SecureArray input; |
2862 | input.resize(size: flen); |
2863 | memcpy(dest: input.data(), src: from, n: input.size()); |
2864 | |
2865 | QCA::SecureArray output; |
2866 | |
2867 | if (self->key.decrypt(in: input, out: &output, alg: algo)) { |
2868 | memcpy(dest: to, src: output.data(), n: output.size()); |
2869 | return output.size(); |
2870 | } |
2871 | |
2872 | // XXX: An error should be set in this case too. |
2873 | return -1; |
2874 | } |
2875 | |
2876 | static int rsa_finish(RSA *rsa) |
2877 | { |
2878 | QCA_RSA_METHOD *self = (QCA_RSA_METHOD *)RSA_get_app_data(rsa); |
2879 | delete self; |
2880 | return 1; |
2881 | } |
2882 | }; |
2883 | |
2884 | static RSA *createFromExisting(const RSAPrivateKey &key) |
2885 | { |
2886 | RSA *r = RSA_new(); |
2887 | new QCA_RSA_METHOD(key, r); // will delete itself on RSA_free |
2888 | return r; |
2889 | } |
2890 | |
2891 | //---------------------------------------------------------------------------- |
2892 | // MyPKeyContext |
2893 | //---------------------------------------------------------------------------- |
2894 | class MyPKeyContext : public PKeyContext |
2895 | { |
2896 | Q_OBJECT |
2897 | public: |
2898 | PKeyBase *k; |
2899 | |
2900 | MyPKeyContext(Provider *p) |
2901 | : PKeyContext(p) |
2902 | { |
2903 | k = nullptr; |
2904 | } |
2905 | |
2906 | ~MyPKeyContext() override |
2907 | { |
2908 | delete k; |
2909 | } |
2910 | |
2911 | Provider::Context *clone() const override |
2912 | { |
2913 | MyPKeyContext *c = new MyPKeyContext(*this); |
2914 | c->k = (PKeyBase *)k->clone(); |
2915 | return c; |
2916 | } |
2917 | |
2918 | QList<PKey::Type> supportedTypes() const override |
2919 | { |
2920 | QList<PKey::Type> list; |
2921 | list += PKey::RSA; |
2922 | list += PKey::DSA; |
2923 | list += PKey::DH; |
2924 | return list; |
2925 | } |
2926 | |
2927 | QList<PKey::Type> supportedIOTypes() const override |
2928 | { |
2929 | QList<PKey::Type> list; |
2930 | list += PKey::RSA; |
2931 | list += PKey::DSA; |
2932 | return list; |
2933 | } |
2934 | |
2935 | QList<PBEAlgorithm> supportedPBEAlgorithms() const override |
2936 | { |
2937 | QList<PBEAlgorithm> list; |
2938 | list += PBES2_DES_SHA1; |
2939 | list += PBES2_TripleDES_SHA1; |
2940 | return list; |
2941 | } |
2942 | |
2943 | PKeyBase *key() override |
2944 | { |
2945 | return k; |
2946 | } |
2947 | |
2948 | const PKeyBase *key() const override |
2949 | { |
2950 | return k; |
2951 | } |
2952 | |
2953 | void setKey(PKeyBase *key) override |
2954 | { |
2955 | k = key; |
2956 | } |
2957 | |
2958 | bool importKey(const PKeyBase *key) override |
2959 | { |
2960 | Q_UNUSED(key); |
2961 | return false; |
2962 | } |
2963 | |
2964 | EVP_PKEY *get_pkey() const |
2965 | { |
2966 | PKey::Type t = k->type(); |
2967 | if (t == PKey::RSA) |
2968 | return static_cast<RSAKey *>(k)->evp.pkey; |
2969 | else if (t == PKey::DSA) |
2970 | return static_cast<DSAKey *>(k)->evp.pkey; |
2971 | else |
2972 | return static_cast<DHKey *>(k)->evp.pkey; |
2973 | } |
2974 | |
2975 | PKeyBase *pkeyToBase(EVP_PKEY *pkey, bool sec) const |
2976 | { |
2977 | PKeyBase *nk = nullptr; |
2978 | int pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey)); |
2979 | if (pkey_type == EVP_PKEY_RSA) { |
2980 | RSAKey *c = new RSAKey(provider()); |
2981 | c->evp.pkey = pkey; |
2982 | c->sec = sec; |
2983 | nk = c; |
2984 | } else if (pkey_type == EVP_PKEY_DSA) { |
2985 | DSAKey *c = new DSAKey(provider()); |
2986 | c->evp.pkey = pkey; |
2987 | c->sec = sec; |
2988 | nk = c; |
2989 | } else if (pkey_type == EVP_PKEY_DH) { |
2990 | DHKey *c = new DHKey(provider()); |
2991 | c->evp.pkey = pkey; |
2992 | c->sec = sec; |
2993 | nk = c; |
2994 | } else { |
2995 | EVP_PKEY_free(pkey); |
2996 | } |
2997 | return nk; |
2998 | } |
2999 | |
3000 | QByteArray publicToDER() const override |
3001 | { |
3002 | EVP_PKEY *pkey = get_pkey(); |
3003 | |
3004 | int pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey)); |
3005 | |
3006 | // OpenSSL does not have DH import/export support |
3007 | if (pkey_type == EVP_PKEY_DH) |
3008 | return QByteArray(); |
3009 | |
3010 | BIO *bo = BIO_new(type: BIO_s_mem()); |
3011 | i2d_PUBKEY_bio(bp: bo, pkey); |
3012 | const QByteArray buf = bio2ba(b: bo); |
3013 | return buf; |
3014 | } |
3015 | |
3016 | QString publicToPEM() const override |
3017 | { |
3018 | EVP_PKEY *pkey = get_pkey(); |
3019 | |
3020 | int pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey)); |
3021 | |
3022 | // OpenSSL does not have DH import/export support |
3023 | if (pkey_type == EVP_PKEY_DH) |
3024 | return QString(); |
3025 | |
3026 | BIO *bo = BIO_new(type: BIO_s_mem()); |
3027 | PEM_write_bio_PUBKEY(out: bo, x: pkey); |
3028 | const QByteArray buf = bio2ba(b: bo); |
3029 | return QString::fromLatin1(ba: buf); |
3030 | } |
3031 | |
3032 | ConvertResult publicFromDER(const QByteArray &in) override |
3033 | { |
3034 | delete k; |
3035 | k = nullptr; |
3036 | |
3037 | BIO *bi = BIO_new(type: BIO_s_mem()); |
3038 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
3039 | EVP_PKEY *pkey = d2i_PUBKEY_bio(bp: bi, a: nullptr); |
3040 | BIO_free(a: bi); |
3041 | |
3042 | if (!pkey) |
3043 | return ErrorDecode; |
3044 | |
3045 | k = pkeyToBase(pkey, sec: false); |
3046 | if (k) |
3047 | return ConvertGood; |
3048 | else |
3049 | return ErrorDecode; |
3050 | } |
3051 | |
3052 | ConvertResult publicFromPEM(const QString &s) override |
3053 | { |
3054 | delete k; |
3055 | k = nullptr; |
3056 | |
3057 | const QByteArray in = s.toLatin1(); |
3058 | BIO *bi = BIO_new(type: BIO_s_mem()); |
3059 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
3060 | EVP_PKEY *pkey = PEM_read_bio_PUBKEY(out: bi, x: nullptr, cb: passphrase_cb, u: nullptr); |
3061 | BIO_free(a: bi); |
3062 | |
3063 | if (!pkey) |
3064 | return ErrorDecode; |
3065 | |
3066 | k = pkeyToBase(pkey, sec: false); |
3067 | if (k) |
3068 | return ConvertGood; |
3069 | else |
3070 | return ErrorDecode; |
3071 | } |
3072 | |
3073 | SecureArray privateToDER(const SecureArray &passphrase, PBEAlgorithm pbe) const override |
3074 | { |
3075 | // if(pbe == PBEDefault) |
3076 | // pbe = PBES2_TripleDES_SHA1; |
3077 | |
3078 | const EVP_CIPHER *cipher = nullptr; |
3079 | if (pbe == PBES2_TripleDES_SHA1) |
3080 | cipher = EVP_des_ede3_cbc(); |
3081 | else if (pbe == PBES2_DES_SHA1) |
3082 | cipher = EVP_des_cbc(); |
3083 | |
3084 | if (!cipher) |
3085 | return SecureArray(); |
3086 | |
3087 | EVP_PKEY *pkey = get_pkey(); |
3088 | int pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey)); |
3089 | |
3090 | // OpenSSL does not have DH import/export support |
3091 | if (pkey_type == EVP_PKEY_DH) |
3092 | return SecureArray(); |
3093 | |
3094 | BIO *bo = BIO_new(type: BIO_s_mem()); |
3095 | if (!passphrase.isEmpty()) |
3096 | i2d_PKCS8PrivateKey_bio(bp: bo, x: pkey, enc: cipher, kstr: nullptr, klen: 0, cb: nullptr, u: (void *)passphrase.data()); |
3097 | else |
3098 | i2d_PKCS8PrivateKey_bio(bp: bo, x: pkey, enc: nullptr, kstr: nullptr, klen: 0, cb: nullptr, u: nullptr); |
3099 | SecureArray buf = bio2buf(b: bo); |
3100 | return buf; |
3101 | } |
3102 | |
3103 | QString privateToPEM(const SecureArray &passphrase, PBEAlgorithm pbe) const override |
3104 | { |
3105 | // if(pbe == PBEDefault) |
3106 | // pbe = PBES2_TripleDES_SHA1; |
3107 | |
3108 | const EVP_CIPHER *cipher = nullptr; |
3109 | if (pbe == PBES2_TripleDES_SHA1) |
3110 | cipher = EVP_des_ede3_cbc(); |
3111 | else if (pbe == PBES2_DES_SHA1) |
3112 | cipher = EVP_des_cbc(); |
3113 | |
3114 | if (!cipher) |
3115 | return QString(); |
3116 | |
3117 | EVP_PKEY *pkey = get_pkey(); |
3118 | int pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey)); |
3119 | |
3120 | // OpenSSL does not have DH import/export support |
3121 | if (pkey_type == EVP_PKEY_DH) |
3122 | return QString(); |
3123 | |
3124 | BIO *bo = BIO_new(type: BIO_s_mem()); |
3125 | if (!passphrase.isEmpty()) |
3126 | PEM_write_bio_PKCS8PrivateKey(bo, pkey, cipher, kstr: nullptr, klen: 0, cb: nullptr, u: (void *)passphrase.data()); |
3127 | else |
3128 | PEM_write_bio_PKCS8PrivateKey(bo, pkey, nullptr, kstr: nullptr, klen: 0, cb: nullptr, u: nullptr); |
3129 | SecureArray buf = bio2buf(b: bo); |
3130 | return QString::fromLatin1(ba: buf.toByteArray()); |
3131 | } |
3132 | |
3133 | ConvertResult privateFromDER(const SecureArray &in, const SecureArray &passphrase) override |
3134 | { |
3135 | delete k; |
3136 | k = nullptr; |
3137 | |
3138 | EVP_PKEY *pkey; |
3139 | if (!passphrase.isEmpty()) |
3140 | pkey = qca_d2i_PKCS8PrivateKey(in, x: nullptr, cb: nullptr, u: (void *)passphrase.data()); |
3141 | else |
3142 | pkey = qca_d2i_PKCS8PrivateKey(in, x: nullptr, cb: passphrase_cb, u: nullptr); |
3143 | |
3144 | if (!pkey) |
3145 | return ErrorDecode; |
3146 | |
3147 | k = pkeyToBase(pkey, sec: true); |
3148 | if (k) |
3149 | return ConvertGood; |
3150 | else |
3151 | return ErrorDecode; |
3152 | } |
3153 | |
3154 | ConvertResult privateFromPEM(const QString &s, const SecureArray &passphrase) override |
3155 | { |
3156 | delete k; |
3157 | k = nullptr; |
3158 | |
3159 | const QByteArray in = s.toLatin1(); |
3160 | BIO *bi = BIO_new(type: BIO_s_mem()); |
3161 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
3162 | EVP_PKEY *pkey; |
3163 | if (!passphrase.isEmpty()) |
3164 | pkey = PEM_read_bio_PrivateKey(out: bi, x: nullptr, cb: nullptr, u: (void *)passphrase.data()); |
3165 | else |
3166 | pkey = PEM_read_bio_PrivateKey(out: bi, x: nullptr, cb: passphrase_cb, u: nullptr); |
3167 | BIO_free(a: bi); |
3168 | |
3169 | if (!pkey) |
3170 | return ErrorDecode; |
3171 | |
3172 | k = pkeyToBase(pkey, sec: true); |
3173 | if (k) |
3174 | return ConvertGood; |
3175 | else |
3176 | return ErrorDecode; |
3177 | } |
3178 | }; |
3179 | |
3180 | //---------------------------------------------------------------------------- |
3181 | // MyCertContext |
3182 | //---------------------------------------------------------------------------- |
3183 | class X509Item |
3184 | { |
3185 | public: |
3186 | X509 *cert; |
3187 | X509_REQ *req; |
3188 | X509_CRL *crl; |
3189 | |
3190 | enum Type |
3191 | { |
3192 | TypeCert, |
3193 | TypeReq, |
3194 | TypeCRL |
3195 | }; |
3196 | |
3197 | X509Item() |
3198 | { |
3199 | cert = nullptr; |
3200 | req = nullptr; |
3201 | crl = nullptr; |
3202 | } |
3203 | |
3204 | X509Item(const X509Item &from) |
3205 | { |
3206 | cert = nullptr; |
3207 | req = nullptr; |
3208 | crl = nullptr; |
3209 | *this = from; |
3210 | } |
3211 | |
3212 | ~X509Item() |
3213 | { |
3214 | reset(); |
3215 | } |
3216 | |
3217 | X509Item &operator=(const X509Item &from) |
3218 | { |
3219 | if (this != &from) { |
3220 | reset(); |
3221 | cert = from.cert; |
3222 | req = from.req; |
3223 | crl = from.crl; |
3224 | |
3225 | if (cert) |
3226 | X509_up_ref(x: cert); |
3227 | if (req) { |
3228 | // Not exposed, so copy |
3229 | req = X509_REQ_dup(a: req); |
3230 | } |
3231 | if (crl) |
3232 | X509_CRL_up_ref(crl); |
3233 | } |
3234 | |
3235 | return *this; |
3236 | } |
3237 | |
3238 | void reset() |
3239 | { |
3240 | if (cert) { |
3241 | X509_free(a: cert); |
3242 | cert = nullptr; |
3243 | } |
3244 | if (req) { |
3245 | X509_REQ_free(a: req); |
3246 | req = nullptr; |
3247 | } |
3248 | if (crl) { |
3249 | X509_CRL_free(a: crl); |
3250 | crl = nullptr; |
3251 | } |
3252 | } |
3253 | |
3254 | bool isNull() const |
3255 | { |
3256 | return (!cert && !req && !crl); |
3257 | } |
3258 | |
3259 | QByteArray toDER() const |
3260 | { |
3261 | BIO *bo = BIO_new(type: BIO_s_mem()); |
3262 | if (cert) |
3263 | i2d_X509_bio(bp: bo, x509: cert); |
3264 | else if (req) |
3265 | i2d_X509_REQ_bio(bp: bo, req); |
3266 | else if (crl) |
3267 | i2d_X509_CRL_bio(bp: bo, crl); |
3268 | const QByteArray buf = bio2ba(b: bo); |
3269 | return buf; |
3270 | } |
3271 | |
3272 | QString toPEM() const |
3273 | { |
3274 | BIO *bo = BIO_new(type: BIO_s_mem()); |
3275 | if (cert) |
3276 | PEM_write_bio_X509(out: bo, x: cert); |
3277 | else if (req) |
3278 | PEM_write_bio_X509_REQ(out: bo, x: req); |
3279 | else if (crl) |
3280 | PEM_write_bio_X509_CRL(out: bo, x: crl); |
3281 | const QByteArray buf = bio2ba(b: bo); |
3282 | return QString::fromLatin1(ba: buf); |
3283 | } |
3284 | |
3285 | ConvertResult fromDER(const QByteArray &in, Type t) |
3286 | { |
3287 | reset(); |
3288 | |
3289 | BIO *bi = BIO_new(type: BIO_s_mem()); |
3290 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
3291 | |
3292 | if (t == TypeCert) |
3293 | cert = d2i_X509_bio(bp: bi, x509: nullptr); |
3294 | else if (t == TypeReq) |
3295 | req = d2i_X509_REQ_bio(bp: bi, req: nullptr); |
3296 | else if (t == TypeCRL) |
3297 | crl = d2i_X509_CRL_bio(bp: bi, crl: nullptr); |
3298 | |
3299 | BIO_free(a: bi); |
3300 | |
3301 | if (isNull()) |
3302 | return ErrorDecode; |
3303 | |
3304 | return ConvertGood; |
3305 | } |
3306 | |
3307 | ConvertResult fromPEM(const QString &s, Type t) |
3308 | { |
3309 | reset(); |
3310 | |
3311 | const QByteArray in = s.toLatin1(); |
3312 | BIO *bi = BIO_new(type: BIO_s_mem()); |
3313 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
3314 | |
3315 | if (t == TypeCert) |
3316 | cert = PEM_read_bio_X509(out: bi, x: nullptr, cb: passphrase_cb, u: nullptr); |
3317 | else if (t == TypeReq) |
3318 | req = PEM_read_bio_X509_REQ(out: bi, x: nullptr, cb: passphrase_cb, u: nullptr); |
3319 | else if (t == TypeCRL) |
3320 | crl = PEM_read_bio_X509_CRL(out: bi, x: nullptr, cb: passphrase_cb, u: nullptr); |
3321 | |
3322 | BIO_free(a: bi); |
3323 | |
3324 | if (isNull()) |
3325 | return ErrorDecode; |
3326 | |
3327 | return ConvertGood; |
3328 | } |
3329 | }; |
3330 | |
3331 | // (taken from kdelibs) -- Justin |
3332 | // |
3333 | // This code is mostly taken from OpenSSL v0.9.5a |
3334 | // by Eric Young |
3335 | QDateTime ASN1_UTCTIME_QDateTime(const ASN1_UTCTIME *tm, int *isGmt) |
3336 | { |
3337 | QDateTime qdt; |
3338 | char *v; |
3339 | int gmt = 0; |
3340 | int i; |
3341 | int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0; |
3342 | QDate qdate; |
3343 | QTime qtime; |
3344 | |
3345 | i = tm->length; |
3346 | v = (char *)tm->data; |
3347 | |
3348 | if (i < 10) |
3349 | goto auq_err; |
3350 | if (v[i - 1] == 'Z') |
3351 | gmt = 1; |
3352 | for (i = 0; i < 10; i++) |
3353 | if ((v[i] > '9') || (v[i] < '0')) |
3354 | goto auq_err; |
3355 | y = (v[0] - '0') * 10 + (v[1] - '0'); |
3356 | if (y < 50) |
3357 | y += 100; |
3358 | M = (v[2] - '0') * 10 + (v[3] - '0'); |
3359 | if ((M > 12) || (M < 1)) |
3360 | goto auq_err; |
3361 | d = (v[4] - '0') * 10 + (v[5] - '0'); |
3362 | h = (v[6] - '0') * 10 + (v[7] - '0'); |
3363 | m = (v[8] - '0') * 10 + (v[9] - '0'); |
3364 | if ((v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9')) |
3365 | s = (v[10] - '0') * 10 + (v[11] - '0'); |
3366 | |
3367 | // localize the date and display it. |
3368 | qdate.setDate(year: y + 1900, month: M, day: d); |
3369 | qtime.setHMS(h, m, s); |
3370 | qdt.setDate(qdate); |
3371 | qdt.setTime(qtime); |
3372 | if (gmt) |
3373 | qdt.setTimeSpec(Qt::UTC); |
3374 | auq_err: |
3375 | if (isGmt) |
3376 | *isGmt = gmt; |
3377 | return qdt; |
3378 | } |
3379 | |
3380 | class MyCertContext; |
3381 | static bool sameChain(STACK_OF(X509) * ossl, const QList<const MyCertContext *> &qca); |
3382 | |
3383 | // TODO: support read/write of multiple info values with the same name |
3384 | class MyCertContext : public CertContext |
3385 | { |
3386 | Q_OBJECT |
3387 | public: |
3388 | X509Item item; |
3389 | CertContextProps _props; |
3390 | |
3391 | MyCertContext(Provider *p) |
3392 | : CertContext(p) |
3393 | { |
3394 | // printf("[%p] ** created\n", this); |
3395 | } |
3396 | |
3397 | MyCertContext(const MyCertContext &from) |
3398 | : CertContext(from) |
3399 | , item(from.item) |
3400 | , _props(from._props) |
3401 | { |
3402 | // printf("[%p] ** created as copy (from [%p])\n", this, &from); |
3403 | } |
3404 | |
3405 | ~MyCertContext() override |
3406 | { |
3407 | // printf("[%p] ** deleted\n", this); |
3408 | } |
3409 | |
3410 | Provider::Context *clone() const override |
3411 | { |
3412 | return new MyCertContext(*this); |
3413 | } |
3414 | |
3415 | QByteArray toDER() const override |
3416 | { |
3417 | return item.toDER(); |
3418 | } |
3419 | |
3420 | QString toPEM() const override |
3421 | { |
3422 | return item.toPEM(); |
3423 | } |
3424 | |
3425 | ConvertResult fromDER(const QByteArray &a) override |
3426 | { |
3427 | _props = CertContextProps(); |
3428 | ConvertResult r = item.fromDER(in: a, t: X509Item::TypeCert); |
3429 | if (r == ConvertGood) |
3430 | make_props(); |
3431 | return r; |
3432 | } |
3433 | |
3434 | ConvertResult fromPEM(const QString &s) override |
3435 | { |
3436 | _props = CertContextProps(); |
3437 | ConvertResult r = item.fromPEM(s, t: X509Item::TypeCert); |
3438 | if (r == ConvertGood) |
3439 | make_props(); |
3440 | return r; |
3441 | } |
3442 | |
3443 | void fromX509(X509 *x) |
3444 | { |
3445 | X509_up_ref(x); |
3446 | item.cert = x; |
3447 | make_props(); |
3448 | } |
3449 | |
3450 | bool createSelfSigned(const CertificateOptions &opts, const PKeyContext &priv) override |
3451 | { |
3452 | _props = CertContextProps(); |
3453 | item.reset(); |
3454 | |
3455 | CertificateInfo info = opts.info(); |
3456 | |
3457 | // Note: removing default constraints, let the app choose these if it wants |
3458 | Constraints constraints = opts.constraints(); |
3459 | // constraints - logic from Botan |
3460 | /*Constraints constraints; |
3461 | if(opts.isCA()) |
3462 | { |
3463 | constraints += KeyCertificateSign; |
3464 | constraints += CRLSign; |
3465 | } |
3466 | else |
3467 | constraints = find_constraints(priv, opts.constraints());*/ |
3468 | |
3469 | EVP_PKEY *pk = static_cast<const MyPKeyContext *>(&priv)->get_pkey(); |
3470 | X509_EXTENSION *ex; |
3471 | |
3472 | const EVP_MD *md; |
3473 | if (priv.key()->type() == PKey::RSA || priv.key()->type() == PKey::DSA) |
3474 | md = EVP_sha256(); |
3475 | else |
3476 | return false; |
3477 | |
3478 | // create |
3479 | X509 *x = X509_new(); |
3480 | X509_set_version(x, version: 2); |
3481 | |
3482 | // serial |
3483 | BIGNUM *bn = bi2bn(n: opts.serialNumber()); |
3484 | BN_to_ASN1_INTEGER(bn, ai: X509_get_serialNumber(x)); |
3485 | BN_free(a: bn); |
3486 | |
3487 | // validity period |
3488 | ASN1_TIME_set(X509_get_notBefore(x), t: opts.notValidBefore().toSecsSinceEpoch()); |
3489 | ASN1_TIME_set(X509_get_notAfter(x), t: opts.notValidAfter().toSecsSinceEpoch()); |
3490 | |
3491 | // public key |
3492 | X509_set_pubkey(x, pkey: pk); |
3493 | |
3494 | // subject |
3495 | X509_NAME *name = new_cert_name(info); |
3496 | X509_set_subject_name(x, name); |
3497 | |
3498 | // issuer == subject |
3499 | X509_set_issuer_name(x, name); |
3500 | |
3501 | // subject key id |
3502 | ex = new_subject_key_id(cert: x); |
3503 | { |
3504 | X509_add_ext(x, ex, loc: -1); |
3505 | X509_EXTENSION_free(a: ex); |
3506 | } |
3507 | |
3508 | // CA mode |
3509 | ex = new_basic_constraints(ca: opts.isCA(), pathlen: opts.pathLimit()); |
3510 | if (ex) { |
3511 | X509_add_ext(x, ex, loc: -1); |
3512 | X509_EXTENSION_free(a: ex); |
3513 | } |
3514 | |
3515 | // subject alt name |
3516 | ex = new_cert_subject_alt_name(info); |
3517 | if (ex) { |
3518 | X509_add_ext(x, ex, loc: -1); |
3519 | X509_EXTENSION_free(a: ex); |
3520 | } |
3521 | |
3522 | // key usage |
3523 | ex = new_cert_key_usage(constraints); |
3524 | if (ex) { |
3525 | X509_add_ext(x, ex, loc: -1); |
3526 | X509_EXTENSION_free(a: ex); |
3527 | } |
3528 | |
3529 | // extended key usage |
3530 | ex = new_cert_ext_key_usage(constraints); |
3531 | if (ex) { |
3532 | X509_add_ext(x, ex, loc: -1); |
3533 | X509_EXTENSION_free(a: ex); |
3534 | } |
3535 | |
3536 | // policies |
3537 | ex = new_cert_policies(policies: opts.policies()); |
3538 | if (ex) { |
3539 | X509_add_ext(x, ex, loc: -1); |
3540 | X509_EXTENSION_free(a: ex); |
3541 | } |
3542 | |
3543 | // finished |
3544 | X509_sign(x, pkey: pk, md); |
3545 | |
3546 | item.cert = x; |
3547 | make_props(); |
3548 | return true; |
3549 | } |
3550 | |
3551 | const CertContextProps *props() const override |
3552 | { |
3553 | // printf("[%p] grabbing props\n", this); |
3554 | return &_props; |
3555 | } |
3556 | |
3557 | bool compare(const CertContext *other) const override |
3558 | { |
3559 | const CertContextProps *a = &_props; |
3560 | const CertContextProps *b = other->props(); |
3561 | |
3562 | PublicKey akey, bkey; |
3563 | PKeyContext *ac = subjectPublicKey(); |
3564 | akey.change(c: ac); |
3565 | PKeyContext *bc = other->subjectPublicKey(); |
3566 | bkey.change(c: bc); |
3567 | |
3568 | // logic from Botan |
3569 | if (a->sig != b->sig || a->sigalgo != b->sigalgo || akey != bkey) |
3570 | return false; |
3571 | |
3572 | if (a->issuer != b->issuer || a->subject != b->subject) |
3573 | return false; |
3574 | if (a->serial != b->serial || a->version != b->version) |
3575 | return false; |
3576 | if (a->start != b->start || a->end != b->end) |
3577 | return false; |
3578 | |
3579 | return true; |
3580 | } |
3581 | |
3582 | // does a new |
3583 | PKeyContext *subjectPublicKey() const override |
3584 | { |
3585 | MyPKeyContext *kc = new MyPKeyContext(provider()); |
3586 | EVP_PKEY *pkey = X509_get_pubkey(x: item.cert); |
3587 | PKeyBase *kb = kc->pkeyToBase(pkey, sec: false); |
3588 | kc->setKey(kb); |
3589 | return kc; |
3590 | } |
3591 | |
3592 | bool isIssuerOf(const CertContext *other) const override |
3593 | { |
3594 | // to check a single issuer, we make a list of 1 |
3595 | STACK_OF(X509) *untrusted_list = sk_X509_new_null(); |
3596 | |
3597 | const MyCertContext *our_cc = this; |
3598 | X509 *x = our_cc->item.cert; |
3599 | X509_up_ref(x); |
3600 | sk_X509_push(untrusted_list, x); |
3601 | |
3602 | const MyCertContext *other_cc = static_cast<const MyCertContext *>(other); |
3603 | X509 *ox = other_cc->item.cert; |
3604 | |
3605 | X509_STORE *store = X509_STORE_new(); |
3606 | |
3607 | X509_STORE_CTX *ctx = X509_STORE_CTX_new(); |
3608 | X509_STORE_CTX_init(ctx, trust_store: store, target: ox, untrusted: untrusted_list); |
3609 | |
3610 | // we don't care about the verify result here |
3611 | X509_verify_cert(ctx); |
3612 | |
3613 | // grab the chain, which may not be fully populated |
3614 | STACK_OF(X509) *chain = X509_STORE_CTX_get_chain(ctx); |
3615 | |
3616 | bool ok = false; |
3617 | |
3618 | // chain should be exactly 2 items |
3619 | QList<const MyCertContext *> expected; |
3620 | expected += other_cc; |
3621 | expected += our_cc; |
3622 | if (chain && sameChain(ossl: chain, qca: expected)) |
3623 | ok = true; |
3624 | |
3625 | // cleanup |
3626 | X509_STORE_CTX_free(ctx); |
3627 | X509_STORE_free(v: store); |
3628 | sk_X509_pop_free(untrusted_list, X509_free); |
3629 | |
3630 | return ok; |
3631 | } |
3632 | |
3633 | // implemented later because it depends on MyCRLContext |
3634 | Validity validate(const QList<CertContext *> &trusted, |
3635 | const QList<CertContext *> &untrusted, |
3636 | const QList<CRLContext *> &crls, |
3637 | UsageMode u, |
3638 | ValidateFlags vf) const override; |
3639 | |
3640 | Validity validate_chain(const QList<CertContext *> &chain, |
3641 | const QList<CertContext *> &trusted, |
3642 | const QList<CRLContext *> &crls, |
3643 | UsageMode u, |
3644 | ValidateFlags vf) const override; |
3645 | |
3646 | void make_props() |
3647 | { |
3648 | X509 *x = item.cert; |
3649 | CertContextProps p; |
3650 | |
3651 | p.version = X509_get_version(x); |
3652 | |
3653 | ASN1_INTEGER *ai = X509_get_serialNumber(x); |
3654 | if (ai) { |
3655 | char *rep = i2s_ASN1_INTEGER(meth: nullptr, aint: ai); |
3656 | QString str = QString::fromLatin1(ba: rep); |
3657 | OPENSSL_free(rep); |
3658 | p.serial.fromString(s: str); |
3659 | } |
3660 | |
3661 | p.start = ASN1_UTCTIME_QDateTime(X509_get_notBefore(x), isGmt: nullptr); |
3662 | p.end = ASN1_UTCTIME_QDateTime(X509_get_notAfter(x), isGmt: nullptr); |
3663 | |
3664 | CertificateInfo subject, issuer; |
3665 | |
3666 | subject = get_cert_name(name: X509_get_subject_name(a: x)); |
3667 | issuer = get_cert_name(name: X509_get_issuer_name(a: x)); |
3668 | |
3669 | p.isSelfSigned = (X509_V_OK == X509_check_issued(issuer: x, subject: x)); |
3670 | |
3671 | p.isCA = false; |
3672 | p.pathLimit = 0; |
3673 | int pos = X509_get_ext_by_NID(x, NID_basic_constraints, lastpos: -1); |
3674 | if (pos != -1) { |
3675 | X509_EXTENSION *ex = X509_get_ext(x, loc: pos); |
3676 | if (ex) |
3677 | get_basic_constraints(ex, ca: &p.isCA, pathlen: &p.pathLimit); |
3678 | } |
3679 | |
3680 | pos = X509_get_ext_by_NID(x, NID_subject_alt_name, lastpos: -1); |
3681 | if (pos != -1) { |
3682 | X509_EXTENSION *ex = X509_get_ext(x, loc: pos); |
3683 | if (ex) |
3684 | subject.unite(other: get_cert_alt_name(ex)); |
3685 | } |
3686 | |
3687 | pos = X509_get_ext_by_NID(x, NID_issuer_alt_name, lastpos: -1); |
3688 | if (pos != -1) { |
3689 | X509_EXTENSION *ex = X509_get_ext(x, loc: pos); |
3690 | if (ex) |
3691 | issuer.unite(other: get_cert_alt_name(ex)); |
3692 | } |
3693 | |
3694 | pos = X509_get_ext_by_NID(x, NID_key_usage, lastpos: -1); |
3695 | if (pos != -1) { |
3696 | X509_EXTENSION *ex = X509_get_ext(x, loc: pos); |
3697 | if (ex) |
3698 | p.constraints = get_cert_key_usage(ex); |
3699 | } |
3700 | |
3701 | pos = X509_get_ext_by_NID(x, NID_ext_key_usage, lastpos: -1); |
3702 | if (pos != -1) { |
3703 | X509_EXTENSION *ex = X509_get_ext(x, loc: pos); |
3704 | if (ex) |
3705 | p.constraints += get_cert_ext_key_usage(ex); |
3706 | } |
3707 | |
3708 | pos = X509_get_ext_by_NID(x, NID_certificate_policies, lastpos: -1); |
3709 | if (pos != -1) { |
3710 | X509_EXTENSION *ex = X509_get_ext(x, loc: pos); |
3711 | if (ex) |
3712 | p.policies = get_cert_policies(ex); |
3713 | } |
3714 | |
3715 | const ASN1_BIT_STRING *signature; |
3716 | |
3717 | X509_get0_signature(psig: &signature, palg: nullptr, x); |
3718 | if (signature) { |
3719 | p.sig = QByteArray(signature->length, 0); |
3720 | for (int i = 0; i < signature->length; i++) |
3721 | p.sig[i] = signature->data[i]; |
3722 | } |
3723 | |
3724 | switch (X509_get_signature_nid(x)) { |
3725 | case NID_sha1WithRSAEncryption: |
3726 | p.sigalgo = QCA::EMSA3_SHA1; |
3727 | break; |
3728 | case NID_md5WithRSAEncryption: |
3729 | p.sigalgo = QCA::EMSA3_MD5; |
3730 | break; |
3731 | #ifdef HAVE_OPENSSL_MD2 |
3732 | case NID_md2WithRSAEncryption: |
3733 | p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_MD2 : QCA::SignatureUnknown; |
3734 | break; |
3735 | #endif |
3736 | case NID_ripemd160WithRSA: |
3737 | p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_RIPEMD160 : QCA::SignatureUnknown; |
3738 | break; |
3739 | case NID_dsaWithSHA1: |
3740 | p.sigalgo = QCA::EMSA1_SHA1; |
3741 | break; |
3742 | case NID_sha224WithRSAEncryption: |
3743 | p.sigalgo = QCA::EMSA3_SHA224; |
3744 | break; |
3745 | case NID_sha256WithRSAEncryption: |
3746 | p.sigalgo = QCA::EMSA3_SHA256; |
3747 | break; |
3748 | case NID_sha384WithRSAEncryption: |
3749 | p.sigalgo = QCA::EMSA3_SHA384; |
3750 | break; |
3751 | case NID_sha512WithRSAEncryption: |
3752 | p.sigalgo = QCA::EMSA3_SHA512; |
3753 | break; |
3754 | default: |
3755 | qDebug() << "Unknown signature value: " << X509_get_signature_nid(x); |
3756 | p.sigalgo = QCA::SignatureUnknown; |
3757 | } |
3758 | |
3759 | pos = X509_get_ext_by_NID(x, NID_subject_key_identifier, lastpos: -1); |
3760 | if (pos != -1) { |
3761 | X509_EXTENSION *ex = X509_get_ext(x, loc: pos); |
3762 | if (ex) |
3763 | p.subjectId += get_cert_subject_key_id(ex); |
3764 | } |
3765 | |
3766 | pos = X509_get_ext_by_NID(x, NID_authority_key_identifier, lastpos: -1); |
3767 | if (pos != -1) { |
3768 | X509_EXTENSION *ex = X509_get_ext(x, loc: pos); |
3769 | if (ex) |
3770 | p.issuerId += get_cert_issuer_key_id(ex); |
3771 | } |
3772 | |
3773 | // FIXME: super hack |
3774 | CertificateOptions opts; |
3775 | opts.setInfo(subject); |
3776 | p.subject = opts.infoOrdered(); |
3777 | opts.setInfo(issuer); |
3778 | p.issuer = opts.infoOrdered(); |
3779 | |
3780 | _props = p; |
3781 | // printf("[%p] made props: [%s]\n", this, _props.subject[CommonName].toLatin1().data()); |
3782 | } |
3783 | }; |
3784 | |
3785 | bool sameChain(STACK_OF(X509) * ossl, const QList<const MyCertContext *> &qca) |
3786 | { |
3787 | if (sk_X509_num(ossl) != qca.count()) |
3788 | return false; |
3789 | |
3790 | for (int n = 0; n < sk_X509_num(ossl); ++n) { |
3791 | X509 *a = sk_X509_value(ossl, n); |
3792 | X509 *b = qca[n]->item.cert; |
3793 | if (X509_cmp(a, b) != 0) |
3794 | return false; |
3795 | } |
3796 | |
3797 | return true; |
3798 | } |
3799 | |
3800 | //---------------------------------------------------------------------------- |
3801 | // MyCAContext |
3802 | //---------------------------------------------------------------------------- |
3803 | // Thanks to Pascal Patry |
3804 | class MyCAContext : public CAContext |
3805 | { |
3806 | Q_OBJECT |
3807 | public: |
3808 | X509Item caCert; |
3809 | MyPKeyContext *privateKey; |
3810 | |
3811 | MyCAContext(Provider *p) |
3812 | : CAContext(p) |
3813 | { |
3814 | privateKey = nullptr; |
3815 | } |
3816 | |
3817 | MyCAContext(const MyCAContext &from) |
3818 | : CAContext(from) |
3819 | , caCert(from.caCert) |
3820 | { |
3821 | privateKey = static_cast<MyPKeyContext *>(from.privateKey->clone()); |
3822 | } |
3823 | |
3824 | ~MyCAContext() override |
3825 | { |
3826 | delete privateKey; |
3827 | } |
3828 | |
3829 | CertContext *certificate() const override |
3830 | { |
3831 | MyCertContext *cert = new MyCertContext(provider()); |
3832 | |
3833 | cert->fromX509(x: caCert.cert); |
3834 | return cert; |
3835 | } |
3836 | |
3837 | CertContext *createCertificate(const PKeyContext &pub, const CertificateOptions &opts) const override |
3838 | { |
3839 | // TODO: implement |
3840 | Q_UNUSED(pub) |
3841 | Q_UNUSED(opts) |
3842 | return nullptr; |
3843 | } |
3844 | |
3845 | CRLContext *createCRL(const QDateTime &nextUpdate) const override |
3846 | { |
3847 | // TODO: implement |
3848 | Q_UNUSED(nextUpdate) |
3849 | return nullptr; |
3850 | } |
3851 | |
3852 | void setup(const CertContext &cert, const PKeyContext &priv) override |
3853 | { |
3854 | caCert = static_cast<const MyCertContext &>(cert).item; |
3855 | delete privateKey; |
3856 | privateKey = nullptr; |
3857 | privateKey = static_cast<MyPKeyContext *>(priv.clone()); |
3858 | } |
3859 | |
3860 | CertContext *signRequest(const CSRContext &req, const QDateTime ¬ValidAfter) const override |
3861 | { |
3862 | MyCertContext *cert = nullptr; |
3863 | const EVP_MD *md = nullptr; |
3864 | X509 *x = nullptr; |
3865 | const CertContextProps &props = *req.props(); |
3866 | CertificateOptions subjectOpts; |
3867 | X509_NAME *subjectName = nullptr; |
3868 | X509_EXTENSION *ex = nullptr; |
3869 | |
3870 | if (privateKey->key()->type() == PKey::RSA) |
3871 | md = EVP_sha1(); |
3872 | else if (privateKey->key()->type() == PKey::DSA) |
3873 | md = EVP_sha1(); |
3874 | else |
3875 | return nullptr; |
3876 | |
3877 | cert = new MyCertContext(provider()); |
3878 | |
3879 | subjectOpts.setInfoOrdered(props.subject); |
3880 | subjectName = new_cert_name(info: subjectOpts.info()); |
3881 | |
3882 | // create |
3883 | x = X509_new(); |
3884 | X509_set_version(x, version: 2); |
3885 | |
3886 | // serial |
3887 | BIGNUM *bn = bi2bn(n: props.serial); |
3888 | BN_to_ASN1_INTEGER(bn, ai: X509_get_serialNumber(x)); |
3889 | BN_free(a: bn); |
3890 | |
3891 | // validity period |
3892 | ASN1_TIME_set(X509_get_notBefore(x), t: QDateTime::currentDateTimeUtc().toSecsSinceEpoch()); |
3893 | ASN1_TIME_set(X509_get_notAfter(x), t: notValidAfter.toSecsSinceEpoch()); |
3894 | |
3895 | X509_set_pubkey(x, pkey: static_cast<const MyPKeyContext *>(req.subjectPublicKey())->get_pkey()); |
3896 | X509_set_subject_name(x, name: subjectName); |
3897 | X509_set_issuer_name(x, name: X509_get_subject_name(a: caCert.cert)); |
3898 | |
3899 | // subject key id |
3900 | ex = new_subject_key_id(cert: x); |
3901 | { |
3902 | X509_add_ext(x, ex, loc: -1); |
3903 | X509_EXTENSION_free(a: ex); |
3904 | } |
3905 | |
3906 | // CA mode |
3907 | ex = new_basic_constraints(ca: props.isCA, pathlen: props.pathLimit); |
3908 | if (ex) { |
3909 | X509_add_ext(x, ex, loc: -1); |
3910 | X509_EXTENSION_free(a: ex); |
3911 | } |
3912 | |
3913 | // subject alt name |
3914 | ex = new_cert_subject_alt_name(info: subjectOpts.info()); |
3915 | if (ex) { |
3916 | X509_add_ext(x, ex, loc: -1); |
3917 | X509_EXTENSION_free(a: ex); |
3918 | } |
3919 | |
3920 | // key usage |
3921 | ex = new_cert_key_usage(constraints: props.constraints); |
3922 | if (ex) { |
3923 | X509_add_ext(x, ex, loc: -1); |
3924 | X509_EXTENSION_free(a: ex); |
3925 | } |
3926 | |
3927 | // extended key usage |
3928 | ex = new_cert_ext_key_usage(constraints: props.constraints); |
3929 | if (ex) { |
3930 | X509_add_ext(x, ex, loc: -1); |
3931 | X509_EXTENSION_free(a: ex); |
3932 | } |
3933 | |
3934 | // policies |
3935 | ex = new_cert_policies(policies: props.policies); |
3936 | if (ex) { |
3937 | X509_add_ext(x, ex, loc: -1); |
3938 | X509_EXTENSION_free(a: ex); |
3939 | } |
3940 | |
3941 | if (!X509_sign(x, pkey: privateKey->get_pkey(), md)) { |
3942 | X509_free(a: x); |
3943 | delete cert; |
3944 | return nullptr; |
3945 | } |
3946 | |
3947 | cert->fromX509(x); |
3948 | X509_free(a: x); |
3949 | return cert; |
3950 | } |
3951 | |
3952 | CRLContext * |
3953 | updateCRL(const CRLContext &crl, const QList<CRLEntry> &entries, const QDateTime &nextUpdate) const override |
3954 | { |
3955 | // TODO: implement |
3956 | Q_UNUSED(crl) |
3957 | Q_UNUSED(entries) |
3958 | Q_UNUSED(nextUpdate) |
3959 | return nullptr; |
3960 | } |
3961 | |
3962 | Provider::Context *clone() const override |
3963 | { |
3964 | return new MyCAContext(*this); |
3965 | } |
3966 | }; |
3967 | |
3968 | //---------------------------------------------------------------------------- |
3969 | // MyCSRContext |
3970 | //---------------------------------------------------------------------------- |
3971 | class MyCSRContext : public CSRContext |
3972 | { |
3973 | Q_OBJECT |
3974 | public: |
3975 | X509Item item; |
3976 | CertContextProps _props; |
3977 | |
3978 | MyCSRContext(Provider *p) |
3979 | : CSRContext(p) |
3980 | { |
3981 | } |
3982 | |
3983 | MyCSRContext(const MyCSRContext &from) |
3984 | : CSRContext(from) |
3985 | , item(from.item) |
3986 | , _props(from._props) |
3987 | { |
3988 | } |
3989 | |
3990 | Provider::Context *clone() const override |
3991 | { |
3992 | return new MyCSRContext(*this); |
3993 | } |
3994 | |
3995 | QByteArray toDER() const override |
3996 | { |
3997 | return item.toDER(); |
3998 | } |
3999 | |
4000 | QString toPEM() const override |
4001 | { |
4002 | return item.toPEM(); |
4003 | } |
4004 | |
4005 | ConvertResult fromDER(const QByteArray &a) override |
4006 | { |
4007 | _props = CertContextProps(); |
4008 | ConvertResult r = item.fromDER(in: a, t: X509Item::TypeReq); |
4009 | if (r == ConvertGood) |
4010 | make_props(); |
4011 | return r; |
4012 | } |
4013 | |
4014 | ConvertResult fromPEM(const QString &s) override |
4015 | { |
4016 | _props = CertContextProps(); |
4017 | ConvertResult r = item.fromPEM(s, t: X509Item::TypeReq); |
4018 | if (r == ConvertGood) |
4019 | make_props(); |
4020 | return r; |
4021 | } |
4022 | |
4023 | bool canUseFormat(CertificateRequestFormat f) const override |
4024 | { |
4025 | if (f == PKCS10) |
4026 | return true; |
4027 | return false; |
4028 | } |
4029 | |
4030 | bool createRequest(const CertificateOptions &opts, const PKeyContext &priv) override |
4031 | { |
4032 | _props = CertContextProps(); |
4033 | item.reset(); |
4034 | |
4035 | CertificateInfo info = opts.info(); |
4036 | |
4037 | // Note: removing default constraints, let the app choose these if it wants |
4038 | Constraints constraints = opts.constraints(); |
4039 | // constraints - logic from Botan |
4040 | /*Constraints constraints; |
4041 | if(opts.isCA()) |
4042 | { |
4043 | constraints += KeyCertificateSign; |
4044 | constraints += CRLSign; |
4045 | } |
4046 | else |
4047 | constraints = find_constraints(priv, opts.constraints());*/ |
4048 | |
4049 | EVP_PKEY *pk = static_cast<const MyPKeyContext *>(&priv)->get_pkey(); |
4050 | X509_EXTENSION *ex; |
4051 | |
4052 | const EVP_MD *md; |
4053 | if (priv.key()->type() == PKey::RSA) |
4054 | md = EVP_sha1(); |
4055 | else if (priv.key()->type() == PKey::DSA) |
4056 | md = EVP_sha1(); |
4057 | else |
4058 | return false; |
4059 | |
4060 | // create |
4061 | X509_REQ *x = X509_REQ_new(); |
4062 | |
4063 | // public key |
4064 | X509_REQ_set_pubkey(x, pkey: pk); |
4065 | |
4066 | // subject |
4067 | X509_NAME *name = new_cert_name(info); |
4068 | X509_REQ_set_subject_name(req: x, name); |
4069 | |
4070 | // challenge |
4071 | const QByteArray cs = opts.challenge().toLatin1(); |
4072 | if (!cs.isEmpty()) |
4073 | X509_REQ_add1_attr_by_NID( |
4074 | req: x, NID_pkcs9_challengePassword, MBSTRING_UTF8, bytes: (const unsigned char *)cs.data(), len: -1); |
4075 | |
4076 | STACK_OF(X509_EXTENSION) *exts = sk_X509_EXTENSION_new_null(); |
4077 | |
4078 | // CA mode |
4079 | ex = new_basic_constraints(ca: opts.isCA(), pathlen: opts.pathLimit()); |
4080 | if (ex) |
4081 | sk_X509_EXTENSION_push(exts, ex); |
4082 | |
4083 | // subject alt name |
4084 | ex = new_cert_subject_alt_name(info); |
4085 | if (ex) |
4086 | sk_X509_EXTENSION_push(exts, ex); |
4087 | |
4088 | // key usage |
4089 | ex = new_cert_key_usage(constraints); |
4090 | if (ex) |
4091 | sk_X509_EXTENSION_push(exts, ex); |
4092 | |
4093 | // extended key usage |
4094 | ex = new_cert_ext_key_usage(constraints); |
4095 | if (ex) |
4096 | sk_X509_EXTENSION_push(exts, ex); |
4097 | |
4098 | // policies |
4099 | ex = new_cert_policies(policies: opts.policies()); |
4100 | if (ex) |
4101 | sk_X509_EXTENSION_push(exts, ex); |
4102 | |
4103 | if (sk_X509_EXTENSION_num(exts) > 0) |
4104 | X509_REQ_add_extensions(req: x, ext: exts); |
4105 | sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); |
4106 | |
4107 | // finished |
4108 | X509_REQ_sign(x, pkey: pk, md); |
4109 | |
4110 | item.req = x; |
4111 | make_props(); |
4112 | return true; |
4113 | } |
4114 | |
4115 | const CertContextProps *props() const override |
4116 | { |
4117 | return &_props; |
4118 | } |
4119 | |
4120 | bool compare(const CSRContext *other) const override |
4121 | { |
4122 | const CertContextProps *a = &_props; |
4123 | const CertContextProps *b = other->props(); |
4124 | |
4125 | PublicKey akey, bkey; |
4126 | PKeyContext *ac = subjectPublicKey(); |
4127 | akey.change(c: ac); |
4128 | PKeyContext *bc = other->subjectPublicKey(); |
4129 | bkey.change(c: bc); |
4130 | |
4131 | if (a->sig != b->sig || a->sigalgo != b->sigalgo || akey != bkey) |
4132 | return false; |
4133 | |
4134 | // TODO: Anything else we should compare? |
4135 | |
4136 | return true; |
4137 | } |
4138 | |
4139 | PKeyContext *subjectPublicKey() const override // does a new |
4140 | { |
4141 | MyPKeyContext *kc = new MyPKeyContext(provider()); |
4142 | EVP_PKEY *pkey = X509_REQ_get_pubkey(req: item.req); |
4143 | PKeyBase *kb = kc->pkeyToBase(pkey, sec: false); |
4144 | kc->setKey(kb); |
4145 | return kc; |
4146 | } |
4147 | |
4148 | QString toSPKAC() const override |
4149 | { |
4150 | return QString(); |
4151 | } |
4152 | |
4153 | ConvertResult fromSPKAC(const QString &s) override |
4154 | { |
4155 | Q_UNUSED(s); |
4156 | return ErrorDecode; |
4157 | } |
4158 | |
4159 | void make_props() |
4160 | { |
4161 | X509_REQ *x = item.req; |
4162 | CertContextProps p; |
4163 | |
4164 | // TODO: QString challenge; |
4165 | |
4166 | p.format = PKCS10; |
4167 | |
4168 | CertificateInfo subject; |
4169 | |
4170 | subject = get_cert_name(name: X509_REQ_get_subject_name(req: x)); |
4171 | |
4172 | STACK_OF(X509_EXTENSION) *exts = X509_REQ_get_extensions(req: x); |
4173 | |
4174 | p.isCA = false; |
4175 | p.pathLimit = 0; |
4176 | int pos = X509v3_get_ext_by_NID(x: exts, NID_basic_constraints, lastpos: -1); |
4177 | if (pos != -1) { |
4178 | X509_EXTENSION *ex = X509v3_get_ext(x: exts, loc: pos); |
4179 | if (ex) |
4180 | get_basic_constraints(ex, ca: &p.isCA, pathlen: &p.pathLimit); |
4181 | } |
4182 | |
4183 | pos = X509v3_get_ext_by_NID(x: exts, NID_subject_alt_name, lastpos: -1); |
4184 | if (pos != -1) { |
4185 | X509_EXTENSION *ex = X509v3_get_ext(x: exts, loc: pos); |
4186 | if (ex) |
4187 | subject.unite(other: get_cert_alt_name(ex)); |
4188 | } |
4189 | |
4190 | pos = X509v3_get_ext_by_NID(x: exts, NID_key_usage, lastpos: -1); |
4191 | if (pos != -1) { |
4192 | X509_EXTENSION *ex = X509v3_get_ext(x: exts, loc: pos); |
4193 | if (ex) |
4194 | p.constraints = get_cert_key_usage(ex); |
4195 | } |
4196 | |
4197 | pos = X509v3_get_ext_by_NID(x: exts, NID_ext_key_usage, lastpos: -1); |
4198 | if (pos != -1) { |
4199 | X509_EXTENSION *ex = X509v3_get_ext(x: exts, loc: pos); |
4200 | if (ex) |
4201 | p.constraints += get_cert_ext_key_usage(ex); |
4202 | } |
4203 | |
4204 | pos = X509v3_get_ext_by_NID(x: exts, NID_certificate_policies, lastpos: -1); |
4205 | if (pos != -1) { |
4206 | X509_EXTENSION *ex = X509v3_get_ext(x: exts, loc: pos); |
4207 | if (ex) |
4208 | p.policies = get_cert_policies(ex); |
4209 | } |
4210 | |
4211 | sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); |
4212 | |
4213 | const ASN1_BIT_STRING *signature; |
4214 | |
4215 | X509_REQ_get0_signature(req: x, psig: &signature, palg: nullptr); |
4216 | if (signature) { |
4217 | p.sig = QByteArray(signature->length, 0); |
4218 | for (int i = 0; i < signature->length; i++) |
4219 | p.sig[i] = signature->data[i]; |
4220 | } |
4221 | |
4222 | switch (X509_REQ_get_signature_nid(req: x)) { |
4223 | case NID_sha1WithRSAEncryption: |
4224 | p.sigalgo = QCA::EMSA3_SHA1; |
4225 | break; |
4226 | case NID_md5WithRSAEncryption: |
4227 | p.sigalgo = QCA::EMSA3_MD5; |
4228 | break; |
4229 | #ifdef HAVE_OPENSSL_MD2 |
4230 | case NID_md2WithRSAEncryption: |
4231 | p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_MD2 : QCA::SignatureUnknown; |
4232 | break; |
4233 | #endif |
4234 | case NID_ripemd160WithRSA: |
4235 | p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_RIPEMD160 : QCA::SignatureUnknown; |
4236 | break; |
4237 | case NID_dsaWithSHA1: |
4238 | p.sigalgo = QCA::EMSA1_SHA1; |
4239 | break; |
4240 | default: |
4241 | qDebug() << "Unknown signature value: " << X509_REQ_get_signature_nid(req: x); |
4242 | p.sigalgo = QCA::SignatureUnknown; |
4243 | } |
4244 | |
4245 | // FIXME: super hack |
4246 | CertificateOptions opts; |
4247 | opts.setInfo(subject); |
4248 | p.subject = opts.infoOrdered(); |
4249 | |
4250 | _props = p; |
4251 | } |
4252 | }; |
4253 | |
4254 | //---------------------------------------------------------------------------- |
4255 | // MyCRLContext |
4256 | //---------------------------------------------------------------------------- |
4257 | class MyCRLContext : public CRLContext |
4258 | { |
4259 | Q_OBJECT |
4260 | public: |
4261 | X509Item item; |
4262 | CRLContextProps _props; |
4263 | |
4264 | MyCRLContext(Provider *p) |
4265 | : CRLContext(p) |
4266 | { |
4267 | } |
4268 | |
4269 | MyCRLContext(const MyCRLContext &from) |
4270 | : CRLContext(from) |
4271 | , item(from.item) |
4272 | { |
4273 | } |
4274 | |
4275 | Provider::Context *clone() const override |
4276 | { |
4277 | return new MyCRLContext(*this); |
4278 | } |
4279 | |
4280 | QByteArray toDER() const override |
4281 | { |
4282 | return item.toDER(); |
4283 | } |
4284 | |
4285 | QString toPEM() const override |
4286 | { |
4287 | return item.toPEM(); |
4288 | } |
4289 | |
4290 | ConvertResult fromDER(const QByteArray &a) override |
4291 | { |
4292 | _props = CRLContextProps(); |
4293 | ConvertResult r = item.fromDER(in: a, t: X509Item::TypeCRL); |
4294 | if (r == ConvertGood) |
4295 | make_props(); |
4296 | return r; |
4297 | } |
4298 | |
4299 | ConvertResult fromPEM(const QString &s) override |
4300 | { |
4301 | ConvertResult r = item.fromPEM(s, t: X509Item::TypeCRL); |
4302 | if (r == ConvertGood) |
4303 | make_props(); |
4304 | return r; |
4305 | } |
4306 | |
4307 | void fromX509(X509_CRL *x) |
4308 | { |
4309 | X509_CRL_up_ref(crl: x); |
4310 | item.crl = x; |
4311 | make_props(); |
4312 | } |
4313 | |
4314 | const CRLContextProps *props() const override |
4315 | { |
4316 | return &_props; |
4317 | } |
4318 | |
4319 | bool compare(const CRLContext *other) const override |
4320 | { |
4321 | const CRLContextProps *a = &_props; |
4322 | const CRLContextProps *b = other->props(); |
4323 | |
4324 | if (a->issuer != b->issuer) |
4325 | return false; |
4326 | if (a->number != b->number) |
4327 | return false; |
4328 | if (a->thisUpdate != b->thisUpdate) |
4329 | return false; |
4330 | if (a->nextUpdate != b->nextUpdate) |
4331 | return false; |
4332 | if (a->revoked != b->revoked) |
4333 | return false; |
4334 | if (a->sig != b->sig) |
4335 | return false; |
4336 | if (a->sigalgo != b->sigalgo) |
4337 | return false; |
4338 | if (a->issuerId != b->issuerId) |
4339 | return false; |
4340 | |
4341 | return true; |
4342 | } |
4343 | |
4344 | void make_props() |
4345 | { |
4346 | X509_CRL *x = item.crl; |
4347 | |
4348 | CRLContextProps p; |
4349 | |
4350 | CertificateInfo issuer; |
4351 | |
4352 | issuer = get_cert_name(name: X509_CRL_get_issuer(crl: x)); |
4353 | |
4354 | p.thisUpdate = ASN1_UTCTIME_QDateTime(tm: X509_CRL_get0_lastUpdate(crl: x), isGmt: nullptr); |
4355 | p.nextUpdate = ASN1_UTCTIME_QDateTime(tm: X509_CRL_get0_nextUpdate(crl: x), isGmt: nullptr); |
4356 | |
4357 | STACK_OF(X509_REVOKED) *revokeStack = X509_CRL_get_REVOKED(crl: x); |
4358 | |
4359 | for (int i = 0; i < sk_X509_REVOKED_num(revokeStack); ++i) { |
4360 | X509_REVOKED *rev = sk_X509_REVOKED_value(revokeStack, i); |
4361 | BigInteger serial = bn2bi_free(n: ASN1_INTEGER_to_BN(ai: X509_REVOKED_get0_serialNumber(x: rev), bn: nullptr)); |
4362 | QDateTime time = ASN1_UTCTIME_QDateTime(tm: X509_REVOKED_get0_revocationDate(x: rev), isGmt: nullptr); |
4363 | QCA::CRLEntry::Reason reason = QCA::CRLEntry::Unspecified; |
4364 | int pos = X509_REVOKED_get_ext_by_NID(x: rev, NID_crl_reason, lastpos: -1); |
4365 | if (pos != -1) { |
4366 | X509_EXTENSION *ex = X509_REVOKED_get_ext(x: rev, loc: pos); |
4367 | if (ex) { |
4368 | ASN1_ENUMERATED *result = (ASN1_ENUMERATED *)X509V3_EXT_d2i(ext: ex); |
4369 | switch (ASN1_ENUMERATED_get(a: result)) { |
4370 | case CRL_REASON_UNSPECIFIED: |
4371 | reason = QCA::CRLEntry::Unspecified; |
4372 | break; |
4373 | case CRL_REASON_KEY_COMPROMISE: |
4374 | reason = QCA::CRLEntry::KeyCompromise; |
4375 | break; |
4376 | case CRL_REASON_CA_COMPROMISE: |
4377 | reason = QCA::CRLEntry::CACompromise; |
4378 | break; |
4379 | case CRL_REASON_AFFILIATION_CHANGED: |
4380 | reason = QCA::CRLEntry::AffiliationChanged; |
4381 | break; |
4382 | case CRL_REASON_SUPERSEDED: |
4383 | reason = QCA::CRLEntry::Superseded; |
4384 | break; |
4385 | case CRL_REASON_CESSATION_OF_OPERATION: |
4386 | reason = QCA::CRLEntry::CessationOfOperation; |
4387 | break; |
4388 | case CRL_REASON_CERTIFICATE_HOLD: |
4389 | reason = QCA::CRLEntry::CertificateHold; |
4390 | break; |
4391 | case CRL_REASON_REMOVE_FROM_CRL: |
4392 | reason = QCA::CRLEntry::RemoveFromCRL; |
4393 | break; |
4394 | case CRL_REASON_PRIVILEGE_WITHDRAWN: |
4395 | reason = QCA::CRLEntry::PrivilegeWithdrawn; |
4396 | break; |
4397 | case CRL_REASON_AA_COMPROMISE: |
4398 | reason = QCA::CRLEntry::AACompromise; |
4399 | break; |
4400 | default: |
4401 | reason = QCA::CRLEntry::Unspecified; |
4402 | break; |
4403 | } |
4404 | ASN1_ENUMERATED_free(a: result); |
4405 | } |
4406 | } |
4407 | CRLEntry thisEntry(serial, time, reason); |
4408 | p.revoked.append(t: thisEntry); |
4409 | } |
4410 | |
4411 | const ASN1_BIT_STRING *signature; |
4412 | |
4413 | X509_CRL_get0_signature(crl: x, psig: &signature, palg: nullptr); |
4414 | if (signature) { |
4415 | p.sig = QByteArray(signature->length, 0); |
4416 | for (int i = 0; i < signature->length; i++) |
4417 | p.sig[i] = signature->data[i]; |
4418 | } |
4419 | |
4420 | switch (X509_CRL_get_signature_nid(crl: x)) { |
4421 | case NID_sha1WithRSAEncryption: |
4422 | p.sigalgo = QCA::EMSA3_SHA1; |
4423 | break; |
4424 | case NID_md5WithRSAEncryption: |
4425 | p.sigalgo = QCA::EMSA3_MD5; |
4426 | break; |
4427 | #ifdef HAVE_OPENSSL_MD2 |
4428 | case NID_md2WithRSAEncryption: |
4429 | p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_MD2 : QCA::SignatureUnknown; |
4430 | break; |
4431 | #endif |
4432 | case NID_ripemd160WithRSA: |
4433 | p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_RIPEMD160 : QCA::SignatureUnknown; |
4434 | break; |
4435 | case NID_dsaWithSHA1: |
4436 | p.sigalgo = QCA::EMSA1_SHA1; |
4437 | break; |
4438 | case NID_sha224WithRSAEncryption: |
4439 | p.sigalgo = QCA::EMSA3_SHA224; |
4440 | break; |
4441 | case NID_sha256WithRSAEncryption: |
4442 | p.sigalgo = QCA::EMSA3_SHA256; |
4443 | break; |
4444 | case NID_sha384WithRSAEncryption: |
4445 | p.sigalgo = QCA::EMSA3_SHA384; |
4446 | break; |
4447 | case NID_sha512WithRSAEncryption: |
4448 | p.sigalgo = QCA::EMSA3_SHA512; |
4449 | break; |
4450 | default: |
4451 | qWarning() << "Unknown signature value: " << X509_CRL_get_signature_nid(crl: x); |
4452 | p.sigalgo = QCA::SignatureUnknown; |
4453 | } |
4454 | |
4455 | int pos = X509_CRL_get_ext_by_NID(x, NID_authority_key_identifier, lastpos: -1); |
4456 | if (pos != -1) { |
4457 | X509_EXTENSION *ex = X509_CRL_get_ext(x, loc: pos); |
4458 | if (ex) |
4459 | p.issuerId += get_cert_issuer_key_id(ex); |
4460 | } |
4461 | |
4462 | p.number = -1; |
4463 | pos = X509_CRL_get_ext_by_NID(x, NID_crl_number, lastpos: -1); |
4464 | if (pos != -1) { |
4465 | X509_EXTENSION *ex = X509_CRL_get_ext(x, loc: pos); |
4466 | if (ex) { |
4467 | ASN1_INTEGER *result = (ASN1_INTEGER *)X509V3_EXT_d2i(ext: ex); |
4468 | p.number = ASN1_INTEGER_get(a: result); |
4469 | ASN1_INTEGER_free(a: result); |
4470 | } |
4471 | } |
4472 | |
4473 | // FIXME: super hack |
4474 | CertificateOptions opts; |
4475 | opts.setInfo(issuer); |
4476 | p.issuer = opts.infoOrdered(); |
4477 | |
4478 | _props = p; |
4479 | } |
4480 | }; |
4481 | |
4482 | //---------------------------------------------------------------------------- |
4483 | // MyCertCollectionContext |
4484 | //---------------------------------------------------------------------------- |
4485 | class MyCertCollectionContext : public CertCollectionContext |
4486 | { |
4487 | Q_OBJECT |
4488 | public: |
4489 | MyCertCollectionContext(Provider *p) |
4490 | : CertCollectionContext(p) |
4491 | { |
4492 | } |
4493 | |
4494 | Provider::Context *clone() const override |
4495 | { |
4496 | return new MyCertCollectionContext(*this); |
4497 | } |
4498 | |
4499 | QByteArray toPKCS7(const QList<CertContext *> &certs, const QList<CRLContext *> &crls) const override |
4500 | { |
4501 | // TODO: implement |
4502 | Q_UNUSED(certs); |
4503 | Q_UNUSED(crls); |
4504 | return QByteArray(); |
4505 | } |
4506 | |
4507 | ConvertResult fromPKCS7(const QByteArray &a, QList<CertContext *> *certs, QList<CRLContext *> *crls) const override |
4508 | { |
4509 | BIO *bi = BIO_new(type: BIO_s_mem()); |
4510 | BIO_write(b: bi, data: a.data(), dlen: a.size()); |
4511 | PKCS7 *p7 = d2i_PKCS7_bio(bp: bi, p7: nullptr); |
4512 | BIO_free(a: bi); |
4513 | if (!p7) |
4514 | return ErrorDecode; |
4515 | |
4516 | STACK_OF(X509) *xcerts = nullptr; |
4517 | STACK_OF(X509_CRL) *xcrls = nullptr; |
4518 | |
4519 | int i = OBJ_obj2nid(o: p7->type); |
4520 | if (i == NID_pkcs7_signed) { |
4521 | xcerts = p7->d.sign->cert; |
4522 | xcrls = p7->d.sign->crl; |
4523 | } else if (i == NID_pkcs7_signedAndEnveloped) { |
4524 | xcerts = p7->d.signed_and_enveloped->cert; |
4525 | xcrls = p7->d.signed_and_enveloped->crl; |
4526 | } |
4527 | |
4528 | QList<CertContext *> _certs; |
4529 | QList<CRLContext *> _crls; |
4530 | |
4531 | if (xcerts) { |
4532 | for (int n = 0; n < sk_X509_num(xcerts); ++n) { |
4533 | MyCertContext *cc = new MyCertContext(provider()); |
4534 | cc->fromX509(sk_X509_value(xcerts, n)); |
4535 | _certs += cc; |
4536 | } |
4537 | } |
4538 | if (xcrls) { |
4539 | for (int n = 0; n < sk_X509_CRL_num(xcrls); ++n) { |
4540 | MyCRLContext *cc = new MyCRLContext(provider()); |
4541 | cc->fromX509(sk_X509_CRL_value(xcrls, n)); |
4542 | _crls += cc; |
4543 | } |
4544 | } |
4545 | |
4546 | PKCS7_free(a: p7); |
4547 | |
4548 | *certs = _certs; |
4549 | *crls = _crls; |
4550 | |
4551 | return ConvertGood; |
4552 | } |
4553 | }; |
4554 | |
4555 | static bool usage_check(const MyCertContext &cc, UsageMode u) |
4556 | { |
4557 | if (cc._props.constraints.isEmpty()) { |
4558 | // then any usage is OK |
4559 | return true; |
4560 | } |
4561 | |
4562 | switch (u) { |
4563 | case UsageAny: |
4564 | return true; |
4565 | break; |
4566 | case UsageTLSServer: |
4567 | return cc._props.constraints.contains(t: ServerAuth); |
4568 | break; |
4569 | case UsageTLSClient: |
4570 | return cc._props.constraints.contains(t: ClientAuth); |
4571 | break; |
4572 | case UsageCodeSigning: |
4573 | return cc._props.constraints.contains(t: CodeSigning); |
4574 | break; |
4575 | case UsageEmailProtection: |
4576 | return cc._props.constraints.contains(t: EmailProtection); |
4577 | break; |
4578 | case UsageTimeStamping: |
4579 | return cc._props.constraints.contains(t: TimeStamping); |
4580 | break; |
4581 | case UsageCRLSigning: |
4582 | return cc._props.constraints.contains(t: CRLSign); |
4583 | break; |
4584 | default: |
4585 | return true; |
4586 | } |
4587 | } |
4588 | |
4589 | Validity MyCertContext::validate(const QList<CertContext *> &trusted, |
4590 | const QList<CertContext *> &untrusted, |
4591 | const QList<CRLContext *> &crls, |
4592 | UsageMode u, |
4593 | ValidateFlags vf) const |
4594 | { |
4595 | // TODO |
4596 | Q_UNUSED(vf); |
4597 | |
4598 | STACK_OF(X509) *trusted_list = sk_X509_new_null(); |
4599 | STACK_OF(X509) *untrusted_list = sk_X509_new_null(); |
4600 | QList<X509_CRL *> crl_list; |
4601 | |
4602 | int n; |
4603 | for (n = 0; n < trusted.count(); ++n) { |
4604 | const MyCertContext *cc = static_cast<const MyCertContext *>(trusted[n]); |
4605 | X509 *x = cc->item.cert; |
4606 | X509_up_ref(x); |
4607 | sk_X509_push(trusted_list, x); |
4608 | } |
4609 | for (n = 0; n < untrusted.count(); ++n) { |
4610 | const MyCertContext *cc = static_cast<const MyCertContext *>(untrusted[n]); |
4611 | X509 *x = cc->item.cert; |
4612 | X509_up_ref(x); |
4613 | sk_X509_push(untrusted_list, x); |
4614 | } |
4615 | for (n = 0; n < crls.count(); ++n) { |
4616 | const MyCRLContext *cc = static_cast<const MyCRLContext *>(crls[n]); |
4617 | X509_CRL *x = cc->item.crl; |
4618 | X509_CRL_up_ref(crl: x); |
4619 | crl_list.append(t: x); |
4620 | } |
4621 | |
4622 | const MyCertContext *cc = this; |
4623 | X509 *x = cc->item.cert; |
4624 | |
4625 | // verification happens through a store "context" |
4626 | X509_STORE_CTX *ctx = X509_STORE_CTX_new(); |
4627 | |
4628 | // make a store of crls |
4629 | X509_STORE *store = X509_STORE_new(); |
4630 | for (int n = 0; n < crl_list.count(); ++n) |
4631 | X509_STORE_add_crl(ctx: store, x: crl_list[n]); |
4632 | |
4633 | // the first initialization handles untrusted certs, crls, and target cert |
4634 | X509_STORE_CTX_init(ctx, trust_store: store, target: x, untrusted: untrusted_list); |
4635 | |
4636 | // this initializes the trusted certs |
4637 | X509_STORE_CTX_trusted_stack(ctx, sk: trusted_list); |
4638 | |
4639 | // verify! |
4640 | int ret = X509_verify_cert(ctx); |
4641 | int err = -1; |
4642 | if (!ret) |
4643 | err = X509_STORE_CTX_get_error(ctx); |
4644 | |
4645 | // cleanup |
4646 | X509_STORE_CTX_free(ctx); |
4647 | X509_STORE_free(v: store); |
4648 | |
4649 | sk_X509_pop_free(trusted_list, X509_free); |
4650 | sk_X509_pop_free(untrusted_list, X509_free); |
4651 | for (int n = 0; n < crl_list.count(); ++n) |
4652 | X509_CRL_free(a: crl_list[n]); |
4653 | |
4654 | if (!ret) |
4655 | return convert_verify_error(err); |
4656 | |
4657 | if (!usage_check(cc: *cc, u)) |
4658 | return ErrorInvalidPurpose; |
4659 | |
4660 | return ValidityGood; |
4661 | } |
4662 | |
4663 | Validity MyCertContext::validate_chain(const QList<CertContext *> &chain, |
4664 | const QList<CertContext *> &trusted, |
4665 | const QList<CRLContext *> &crls, |
4666 | UsageMode u, |
4667 | ValidateFlags vf) const |
4668 | { |
4669 | // TODO |
4670 | Q_UNUSED(vf); |
4671 | |
4672 | STACK_OF(X509) *trusted_list = sk_X509_new_null(); |
4673 | STACK_OF(X509) *untrusted_list = sk_X509_new_null(); |
4674 | QList<X509_CRL *> crl_list; |
4675 | |
4676 | int n; |
4677 | for (n = 0; n < trusted.count(); ++n) { |
4678 | const MyCertContext *cc = static_cast<const MyCertContext *>(trusted[n]); |
4679 | X509 *x = cc->item.cert; |
4680 | X509_up_ref(x); |
4681 | sk_X509_push(trusted_list, x); |
4682 | } |
4683 | for (n = 1; n < chain.count(); ++n) { |
4684 | const MyCertContext *cc = static_cast<const MyCertContext *>(chain[n]); |
4685 | X509 *x = cc->item.cert; |
4686 | X509_up_ref(x); |
4687 | sk_X509_push(untrusted_list, x); |
4688 | } |
4689 | for (n = 0; n < crls.count(); ++n) { |
4690 | const MyCRLContext *cc = static_cast<const MyCRLContext *>(crls[n]); |
4691 | X509_CRL *x = cc->item.crl; |
4692 | X509_CRL_up_ref(crl: x); |
4693 | crl_list.append(t: x); |
4694 | } |
4695 | |
4696 | const MyCertContext *cc = static_cast<const MyCertContext *>(chain[0]); |
4697 | X509 *x = cc->item.cert; |
4698 | |
4699 | // verification happens through a store "context" |
4700 | X509_STORE_CTX *ctx = X509_STORE_CTX_new(); |
4701 | |
4702 | // make a store of crls |
4703 | X509_STORE *store = X509_STORE_new(); |
4704 | for (int n = 0; n < crl_list.count(); ++n) |
4705 | X509_STORE_add_crl(ctx: store, x: crl_list[n]); |
4706 | |
4707 | // the first initialization handles untrusted certs, crls, and target cert |
4708 | X509_STORE_CTX_init(ctx, trust_store: store, target: x, untrusted: untrusted_list); |
4709 | |
4710 | // this initializes the trusted certs |
4711 | X509_STORE_CTX_trusted_stack(ctx, sk: trusted_list); |
4712 | |
4713 | // verify! |
4714 | int ret = X509_verify_cert(ctx); |
4715 | int err = -1; |
4716 | if (!ret) |
4717 | err = X509_STORE_CTX_get_error(ctx); |
4718 | |
4719 | // grab the chain, which may not be fully populated |
4720 | STACK_OF(X509) *xchain = X509_STORE_CTX_get_chain(ctx); |
4721 | |
4722 | // make sure the chain is what we expect. the reason we need to do |
4723 | // this is because I don't think openssl cares about the order of |
4724 | // input. that is, if there's a chain A<-B<-C, and we input A as |
4725 | // the base cert, with B and C as the issuers, we will get a |
4726 | // successful validation regardless of whether the issuer list is |
4727 | // in the order B,C or C,B. we don't want an input chain of A,C,B |
4728 | // to be considered correct, so we must account for that here. |
4729 | QList<const MyCertContext *> expected; |
4730 | for (int n = 0; n < chain.count(); ++n) |
4731 | expected += static_cast<const MyCertContext *>(chain[n]); |
4732 | if (!xchain || !sameChain(ossl: xchain, qca: expected)) |
4733 | err = ErrorValidityUnknown; |
4734 | |
4735 | // cleanup |
4736 | X509_STORE_CTX_free(ctx); |
4737 | X509_STORE_free(v: store); |
4738 | |
4739 | sk_X509_pop_free(trusted_list, X509_free); |
4740 | sk_X509_pop_free(untrusted_list, X509_free); |
4741 | for (int n = 0; n < crl_list.count(); ++n) |
4742 | X509_CRL_free(a: crl_list[n]); |
4743 | |
4744 | if (!ret) |
4745 | return convert_verify_error(err); |
4746 | |
4747 | if (!usage_check(cc: *cc, u)) |
4748 | return ErrorInvalidPurpose; |
4749 | |
4750 | return ValidityGood; |
4751 | } |
4752 | |
4753 | class MyPKCS12Context : public PKCS12Context |
4754 | { |
4755 | Q_OBJECT |
4756 | public: |
4757 | MyPKCS12Context(Provider *p) |
4758 | : PKCS12Context(p) |
4759 | { |
4760 | } |
4761 | |
4762 | ~MyPKCS12Context() override |
4763 | { |
4764 | } |
4765 | |
4766 | Provider::Context *clone() const override |
4767 | { |
4768 | return nullptr; |
4769 | } |
4770 | |
4771 | QByteArray toPKCS12(const QString &name, |
4772 | const QList<const CertContext *> &chain, |
4773 | const PKeyContext &priv, |
4774 | const SecureArray &passphrase) const override |
4775 | { |
4776 | if (chain.count() < 1) |
4777 | return QByteArray(); |
4778 | |
4779 | X509 *cert = static_cast<const MyCertContext *>(chain[0])->item.cert; |
4780 | STACK_OF(X509) *ca = sk_X509_new_null(); |
4781 | if (chain.count() > 1) { |
4782 | for (int n = 1; n < chain.count(); ++n) { |
4783 | X509 *x = static_cast<const MyCertContext *>(chain[n])->item.cert; |
4784 | X509_up_ref(x); |
4785 | sk_X509_push(ca, x); |
4786 | } |
4787 | } |
4788 | const MyPKeyContext &pk = static_cast<const MyPKeyContext &>(priv); |
4789 | PKCS12 *p12 = PKCS12_create( |
4790 | pass: (char *)passphrase.data(), name: (char *)name.toLatin1().data(), pkey: pk.get_pkey(), cert, ca, nid_key: 0, nid_cert: 0, iter: 0, mac_iter: 0, keytype: 0); |
4791 | sk_X509_pop_free(ca, X509_free); |
4792 | |
4793 | if (!p12) |
4794 | return QByteArray(); |
4795 | |
4796 | BIO *bo = BIO_new(type: BIO_s_mem()); |
4797 | i2d_PKCS12_bio(bp: bo, p12); |
4798 | const QByteArray out = bio2ba(b: bo); |
4799 | return out; |
4800 | } |
4801 | |
4802 | ConvertResult fromPKCS12(const QByteArray &in, |
4803 | const SecureArray &passphrase, |
4804 | QString *name, |
4805 | QList<CertContext *> *chain, |
4806 | PKeyContext **priv) const override |
4807 | { |
4808 | BIO *bi = BIO_new(type: BIO_s_mem()); |
4809 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
4810 | PKCS12 *p12 = d2i_PKCS12_bio(bp: bi, p12: nullptr); |
4811 | BIO_free(a: bi); |
4812 | if (!p12) |
4813 | return ErrorDecode; |
4814 | |
4815 | EVP_PKEY *pkey; |
4816 | X509 *cert; |
4817 | STACK_OF(X509) *ca = nullptr; |
4818 | if (!PKCS12_parse(p12, pass: passphrase.data(), pkey: &pkey, cert: &cert, ca: &ca)) { |
4819 | PKCS12_free(a: p12); |
4820 | return ErrorDecode; |
4821 | } |
4822 | PKCS12_free(a: p12); |
4823 | |
4824 | // require private key |
4825 | if (!pkey) { |
4826 | if (cert) |
4827 | X509_free(a: cert); |
4828 | if (ca) |
4829 | sk_X509_pop_free(ca, X509_free); |
4830 | return ErrorDecode; |
4831 | } |
4832 | |
4833 | // TODO: require cert |
4834 | |
4835 | int aliasLength; |
4836 | char *aliasData = (char *)X509_alias_get0(x: cert, len: &aliasLength); |
4837 | *name = QString::fromLatin1(str: aliasData, size: aliasLength); |
4838 | |
4839 | MyPKeyContext *pk = new MyPKeyContext(provider()); |
4840 | PKeyBase *k = pk->pkeyToBase(pkey, sec: true); // does an EVP_PKEY_free() |
4841 | if (!k) { |
4842 | delete pk; |
4843 | if (cert) |
4844 | X509_free(a: cert); |
4845 | if (ca) |
4846 | sk_X509_pop_free(ca, X509_free); |
4847 | return ErrorDecode; |
4848 | } |
4849 | pk->k = k; |
4850 | *priv = pk; |
4851 | |
4852 | QList<CertContext *> certs; |
4853 | if (cert) { |
4854 | MyCertContext *cc = new MyCertContext(provider()); |
4855 | cc->fromX509(x: cert); |
4856 | certs.append(t: cc); |
4857 | X509_free(a: cert); |
4858 | } |
4859 | if (ca) { |
4860 | // TODO: reorder in chain-order? |
4861 | // TODO: throw out certs that don't fit the chain? |
4862 | for (int n = 0; n < sk_X509_num(ca); ++n) { |
4863 | MyCertContext *cc = new MyCertContext(provider()); |
4864 | cc->fromX509(sk_X509_value(ca, n)); |
4865 | certs.append(t: cc); |
4866 | } |
4867 | sk_X509_pop_free(ca, X509_free); |
4868 | } |
4869 | |
4870 | // reorder, throw out |
4871 | QCA::CertificateChain ch; |
4872 | for (int n = 0; n < certs.count(); ++n) { |
4873 | QCA::Certificate cert; |
4874 | cert.change(c: certs[n]); |
4875 | ch += cert; |
4876 | } |
4877 | certs.clear(); |
4878 | ch = ch.complete(issuers: QList<QCA::Certificate>()); |
4879 | for (int n = 0; n < ch.count(); ++n) { |
4880 | MyCertContext *cc = (MyCertContext *)ch[n].context(); |
4881 | certs += (new MyCertContext(*cc)); |
4882 | } |
4883 | ch.clear(); |
4884 | |
4885 | *chain = certs; |
4886 | return ConvertGood; |
4887 | } |
4888 | }; |
4889 | |
4890 | // TODO: test to ensure there is no cert-test lag |
4891 | static bool ssl_init = false; |
4892 | class MyTLSContext : public TLSContext |
4893 | { |
4894 | Q_OBJECT |
4895 | public: |
4896 | enum |
4897 | { |
4898 | Good, |
4899 | TryAgain, |
4900 | Bad |
4901 | }; |
4902 | enum |
4903 | { |
4904 | Idle, |
4905 | Connect, |
4906 | Accept, |
4907 | Handshake, |
4908 | Active, |
4909 | Closing |
4910 | }; |
4911 | |
4912 | bool serv; // true if we are acting as a server |
4913 | int mode; |
4914 | QByteArray sendQueue; |
4915 | QByteArray recvQueue; |
4916 | |
4917 | CertificateCollection trusted; |
4918 | Certificate cert, peercert; // TODO: support cert chains |
4919 | PrivateKey key; |
4920 | QString targetHostName; |
4921 | |
4922 | Result result_result; |
4923 | QByteArray result_to_net; |
4924 | int result_encoded; |
4925 | QByteArray result_plain; |
4926 | |
4927 | SSL *ssl; |
4928 | const SSL_METHOD *method; |
4929 | SSL_CTX *context; |
4930 | BIO *rbio, *wbio; |
4931 | Validity vr; |
4932 | bool v_eof; |
4933 | |
4934 | MyTLSContext(Provider *p) |
4935 | : TLSContext(p, QStringLiteral("tls" )) |
4936 | { |
4937 | if (!ssl_init) { |
4938 | SSL_library_init(); |
4939 | SSL_load_error_strings(); |
4940 | ssl_init = true; |
4941 | } |
4942 | |
4943 | ssl = nullptr; |
4944 | context = nullptr; |
4945 | reset(); |
4946 | } |
4947 | |
4948 | ~MyTLSContext() override |
4949 | { |
4950 | reset(); |
4951 | } |
4952 | |
4953 | Provider::Context *clone() const override |
4954 | { |
4955 | return nullptr; |
4956 | } |
4957 | |
4958 | void reset() override |
4959 | { |
4960 | if (ssl) { |
4961 | SSL_free(ssl); |
4962 | ssl = nullptr; |
4963 | } |
4964 | if (context) { |
4965 | SSL_CTX_free(context); |
4966 | context = nullptr; |
4967 | } |
4968 | |
4969 | cert = Certificate(); |
4970 | key = PrivateKey(); |
4971 | |
4972 | sendQueue.resize(size: 0); |
4973 | recvQueue.resize(size: 0); |
4974 | mode = Idle; |
4975 | peercert = Certificate(); |
4976 | vr = ErrorValidityUnknown; |
4977 | v_eof = false; |
4978 | } |
4979 | |
4980 | // dummy verification function for SSL_set_verify() |
4981 | static int ssl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) |
4982 | { |
4983 | Q_UNUSED(preverify_ok); |
4984 | Q_UNUSED(x509_ctx); |
4985 | |
4986 | // don't terminate handshake in case of verification failure |
4987 | return 1; |
4988 | } |
4989 | |
4990 | QStringList supportedCipherSuites(const TLS::Version &version) const override |
4991 | { |
4992 | OpenSSL_add_ssl_algorithms(); |
4993 | SSL_CTX *ctx = nullptr; |
4994 | switch (version) { |
4995 | #ifndef OPENSSL_NO_SSL3_METHOD |
4996 | case TLS::SSL_v3: |
4997 | // Here should be used TLS_client_method() but on Fedora |
4998 | // it doesn't return any SSL ciphers. |
4999 | ctx = SSL_CTX_new(SSLv3_client_method()); |
5000 | SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION); |
5001 | SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION); |
5002 | break; |
5003 | #endif |
5004 | case TLS::TLS_v1: |
5005 | ctx = SSL_CTX_new(meth: TLS_client_method()); |
5006 | SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); |
5007 | SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION); |
5008 | break; |
5009 | case TLS::DTLS_v1: |
5010 | default: |
5011 | /* should not happen - should be in a "dtls" provider*/ |
5012 | qWarning(msg: "Unexpected enum in cipherSuites" ); |
5013 | ctx = nullptr; |
5014 | } |
5015 | if (nullptr == ctx) |
5016 | return QStringList(); |
5017 | |
5018 | SSL *ssl = SSL_new(ctx); |
5019 | if (nullptr == ssl) { |
5020 | SSL_CTX_free(ctx); |
5021 | return QStringList(); |
5022 | } |
5023 | |
5024 | STACK_OF(SSL_CIPHER) *sk = SSL_get1_supported_ciphers(s: ssl); |
5025 | QStringList cipherList; |
5026 | for (int i = 0; i < sk_SSL_CIPHER_num(sk); ++i) { |
5027 | const SSL_CIPHER *thisCipher = sk_SSL_CIPHER_value(sk, i); |
5028 | cipherList += QString::fromLatin1(ba: SSL_CIPHER_standard_name(c: thisCipher)); |
5029 | } |
5030 | sk_SSL_CIPHER_free(sk); |
5031 | |
5032 | SSL_free(ssl); |
5033 | SSL_CTX_free(ctx); |
5034 | |
5035 | return cipherList; |
5036 | } |
5037 | |
5038 | bool canCompress() const override |
5039 | { |
5040 | // TODO |
5041 | return false; |
5042 | } |
5043 | |
5044 | bool canSetHostName() const override |
5045 | { |
5046 | // TODO |
5047 | return false; |
5048 | } |
5049 | |
5050 | int maxSSF() const override |
5051 | { |
5052 | // TODO |
5053 | return 256; |
5054 | } |
5055 | |
5056 | void setConstraints(int minSSF, int maxSSF) override |
5057 | { |
5058 | // TODO |
5059 | Q_UNUSED(minSSF); |
5060 | Q_UNUSED(maxSSF); |
5061 | } |
5062 | |
5063 | void setConstraints(const QStringList &cipherSuiteList) override |
5064 | { |
5065 | // TODO |
5066 | Q_UNUSED(cipherSuiteList); |
5067 | } |
5068 | |
5069 | void setup(bool serverMode, const QString &hostName, bool compress) override |
5070 | { |
5071 | serv = serverMode; |
5072 | if (false == serverMode) { |
5073 | // client |
5074 | targetHostName = hostName; |
5075 | } |
5076 | Q_UNUSED(compress); // TODO |
5077 | } |
5078 | |
5079 | void setTrustedCertificates(const CertificateCollection &_trusted) override |
5080 | { |
5081 | trusted = _trusted; |
5082 | } |
5083 | |
5084 | void setIssuerList(const QList<CertificateInfoOrdered> &issuerList) override |
5085 | { |
5086 | Q_UNUSED(issuerList); // TODO |
5087 | } |
5088 | |
5089 | void setCertificate(const CertificateChain &_cert, const PrivateKey &_key) override |
5090 | { |
5091 | if (!_cert.isEmpty()) |
5092 | cert = _cert.primary(); // TODO: take the whole chain |
5093 | key = _key; |
5094 | } |
5095 | |
5096 | void setSessionId(const TLSSessionContext &id) override |
5097 | { |
5098 | // TODO |
5099 | Q_UNUSED(id); |
5100 | } |
5101 | |
5102 | void shutdown() override |
5103 | { |
5104 | mode = Closing; |
5105 | } |
5106 | |
5107 | void start() override |
5108 | { |
5109 | bool ok; |
5110 | if (serv) |
5111 | ok = priv_startServer(); |
5112 | else |
5113 | ok = priv_startClient(); |
5114 | result_result = ok ? Success : Error; |
5115 | |
5116 | doResultsReady(); |
5117 | } |
5118 | |
5119 | void update(const QByteArray &from_net, const QByteArray &from_app) override |
5120 | { |
5121 | if (mode == Active) { |
5122 | bool ok = true; |
5123 | if (!from_app.isEmpty()) |
5124 | ok = priv_encode(plain: from_app, to_net: &result_to_net, enc: &result_encoded); |
5125 | if (ok) |
5126 | ok = priv_decode(from_net, plain: &result_plain, to_net: &result_to_net); |
5127 | result_result = ok ? Success : Error; |
5128 | } else if (mode == Closing) |
5129 | result_result = priv_shutdown(from_net, to_net: &result_to_net); |
5130 | else |
5131 | result_result = priv_handshake(from_net, to_net: &result_to_net); |
5132 | |
5133 | // printf("update (from_net=%d, to_net=%d, from_app=%d, to_app=%d)\n", from_net.size(), result_to_net.size(), |
5134 | // from_app.size(), result_plain.size()); |
5135 | |
5136 | doResultsReady(); |
5137 | } |
5138 | |
5139 | bool priv_startClient() |
5140 | { |
5141 | // serv = false; |
5142 | method = SSLv23_client_method(); |
5143 | if (!init()) |
5144 | return false; |
5145 | mode = Connect; |
5146 | return true; |
5147 | } |
5148 | |
5149 | bool priv_startServer() |
5150 | { |
5151 | // serv = true; |
5152 | method = SSLv23_server_method(); |
5153 | if (!init()) |
5154 | return false; |
5155 | mode = Accept; |
5156 | return true; |
5157 | } |
5158 | |
5159 | Result priv_handshake(const QByteArray &from_net, QByteArray *to_net) |
5160 | { |
5161 | if (!from_net.isEmpty()) |
5162 | BIO_write(b: rbio, data: from_net.data(), dlen: from_net.size()); |
5163 | |
5164 | if (mode == Connect) { |
5165 | int ret = doConnect(); |
5166 | if (ret == Good) { |
5167 | mode = Handshake; |
5168 | } else if (ret == Bad) { |
5169 | reset(); |
5170 | return Error; |
5171 | } |
5172 | } |
5173 | |
5174 | if (mode == Accept) { |
5175 | int ret = doAccept(); |
5176 | if (ret == Good) { |
5177 | getCert(); |
5178 | mode = Active; |
5179 | } else if (ret == Bad) { |
5180 | reset(); |
5181 | return Error; |
5182 | } |
5183 | } |
5184 | |
5185 | if (mode == Handshake) { |
5186 | int ret = doHandshake(); |
5187 | if (ret == Good) { |
5188 | getCert(); |
5189 | mode = Active; |
5190 | } else if (ret == Bad) { |
5191 | reset(); |
5192 | return Error; |
5193 | } |
5194 | } |
5195 | |
5196 | // process outgoing |
5197 | *to_net = readOutgoing(); |
5198 | |
5199 | if (mode == Active) |
5200 | return Success; |
5201 | else |
5202 | return Continue; |
5203 | } |
5204 | |
5205 | Result priv_shutdown(const QByteArray &from_net, QByteArray *to_net) |
5206 | { |
5207 | if (!from_net.isEmpty()) |
5208 | BIO_write(b: rbio, data: from_net.data(), dlen: from_net.size()); |
5209 | |
5210 | int ret = doShutdown(); |
5211 | if (ret == Bad) { |
5212 | reset(); |
5213 | return Error; |
5214 | } |
5215 | |
5216 | *to_net = readOutgoing(); |
5217 | |
5218 | if (ret == Good) { |
5219 | mode = Idle; |
5220 | return Success; |
5221 | } else { |
5222 | // mode = Closing; |
5223 | return Continue; |
5224 | } |
5225 | } |
5226 | |
5227 | bool priv_encode(const QByteArray &plain, QByteArray *to_net, int *enc) |
5228 | { |
5229 | if (mode != Active) |
5230 | return false; |
5231 | sendQueue.append(a: plain); |
5232 | |
5233 | int encoded = 0; |
5234 | if (sendQueue.size() > 0) { |
5235 | int ret = SSL_write(ssl, buf: sendQueue.data(), num: sendQueue.size()); |
5236 | |
5237 | enum |
5238 | { |
5239 | Good, |
5240 | Continue, |
5241 | Done, |
5242 | Error |
5243 | }; |
5244 | int m; |
5245 | if (ret <= 0) { |
5246 | int x = SSL_get_error(s: ssl, ret_code: ret); |
5247 | if (x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) |
5248 | m = Continue; |
5249 | else if (x == SSL_ERROR_ZERO_RETURN) |
5250 | m = Done; |
5251 | else |
5252 | m = Error; |
5253 | } else { |
5254 | m = Good; |
5255 | encoded = ret; |
5256 | int newsize = sendQueue.size() - encoded; |
5257 | char *r = sendQueue.data(); |
5258 | memmove(dest: r, src: r + encoded, n: newsize); |
5259 | sendQueue.resize(size: newsize); |
5260 | } |
5261 | |
5262 | if (m == Done) { |
5263 | sendQueue.resize(size: 0); |
5264 | v_eof = true; |
5265 | return false; |
5266 | } |
5267 | if (m == Error) { |
5268 | sendQueue.resize(size: 0); |
5269 | return false; |
5270 | } |
5271 | } |
5272 | |
5273 | *to_net += readOutgoing(); |
5274 | *enc = encoded; |
5275 | return true; |
5276 | } |
5277 | |
5278 | bool priv_decode(const QByteArray &from_net, QByteArray *plain, QByteArray *to_net) |
5279 | { |
5280 | if (mode != Active) |
5281 | return false; |
5282 | if (!from_net.isEmpty()) |
5283 | BIO_write(b: rbio, data: from_net.data(), dlen: from_net.size()); |
5284 | |
5285 | QByteArray a; |
5286 | while (!v_eof) { |
5287 | a.resize(size: 8192); |
5288 | int ret = SSL_read(ssl, buf: a.data(), num: a.size()); |
5289 | // printf("SSL_read = %d\n", ret); |
5290 | if (ret > 0) { |
5291 | if (ret != (int)a.size()) |
5292 | a.resize(size: ret); |
5293 | // printf("SSL_read chunk: [%s]\n", qPrintable(arrayToHex(a))); |
5294 | recvQueue.append(a); |
5295 | } else if (ret <= 0) { |
5296 | ERR_print_errors_fp(stdout); |
5297 | int x = SSL_get_error(s: ssl, ret_code: ret); |
5298 | // printf("SSL_read error = %d\n", x); |
5299 | if (x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) |
5300 | break; |
5301 | else if (x == SSL_ERROR_ZERO_RETURN) |
5302 | v_eof = true; |
5303 | else |
5304 | return false; |
5305 | } |
5306 | } |
5307 | |
5308 | *plain = recvQueue; |
5309 | recvQueue.resize(size: 0); |
5310 | |
5311 | // could be outgoing data also |
5312 | *to_net += readOutgoing(); |
5313 | return true; |
5314 | } |
5315 | |
5316 | bool waitForResultsReady(int msecs) override |
5317 | { |
5318 | // TODO: for now, all operations block anyway |
5319 | Q_UNUSED(msecs); |
5320 | return true; |
5321 | } |
5322 | |
5323 | Result result() const override |
5324 | { |
5325 | return result_result; |
5326 | } |
5327 | |
5328 | QByteArray to_net() override |
5329 | { |
5330 | const QByteArray a = result_to_net; |
5331 | result_to_net.clear(); |
5332 | return a; |
5333 | } |
5334 | |
5335 | int encoded() const override |
5336 | { |
5337 | return result_encoded; |
5338 | } |
5339 | |
5340 | QByteArray to_app() override |
5341 | { |
5342 | const QByteArray a = result_plain; |
5343 | result_plain.clear(); |
5344 | return a; |
5345 | } |
5346 | |
5347 | bool eof() const override |
5348 | { |
5349 | return v_eof; |
5350 | } |
5351 | |
5352 | bool clientHelloReceived() const override |
5353 | { |
5354 | // TODO |
5355 | return false; |
5356 | } |
5357 | |
5358 | bool serverHelloReceived() const override |
5359 | { |
5360 | // TODO |
5361 | return false; |
5362 | } |
5363 | |
5364 | QString hostName() const override |
5365 | { |
5366 | // TODO |
5367 | return QString(); |
5368 | } |
5369 | |
5370 | bool certificateRequested() const override |
5371 | { |
5372 | // TODO |
5373 | return false; |
5374 | } |
5375 | |
5376 | QList<CertificateInfoOrdered> issuerList() const override |
5377 | { |
5378 | // TODO |
5379 | return QList<CertificateInfoOrdered>(); |
5380 | } |
5381 | |
5382 | SessionInfo sessionInfo() const override |
5383 | { |
5384 | SessionInfo sessInfo; |
5385 | |
5386 | SSL_SESSION *session = SSL_get0_session(ssl); |
5387 | sessInfo.isCompressed = (0 != SSL_SESSION_get_compress_id(s: session)); |
5388 | int ssl_version = SSL_version(ssl); |
5389 | |
5390 | if (ssl_version == TLS1_VERSION) |
5391 | sessInfo.version = TLS::TLS_v1; |
5392 | else if (ssl_version == SSL3_VERSION) |
5393 | sessInfo.version = TLS::SSL_v3; |
5394 | else if (ssl_version == SSL2_VERSION) |
5395 | sessInfo.version = TLS::SSL_v2; |
5396 | else { |
5397 | qDebug(msg: "unexpected version response" ); |
5398 | sessInfo.version = TLS::TLS_v1; |
5399 | } |
5400 | |
5401 | sessInfo.cipherSuite = QString::fromLatin1(ba: SSL_CIPHER_standard_name(c: SSL_get_current_cipher(s: ssl))); |
5402 | |
5403 | sessInfo.cipherMaxBits = SSL_get_cipher_bits(ssl, &(sessInfo.cipherBits)); |
5404 | |
5405 | sessInfo.id = nullptr; // TODO: session resuming |
5406 | |
5407 | return sessInfo; |
5408 | } |
5409 | |
5410 | QByteArray unprocessed() override |
5411 | { |
5412 | QByteArray a; |
5413 | int size = BIO_pending(rbio); |
5414 | if (size <= 0) |
5415 | return a; |
5416 | a.resize(size); |
5417 | |
5418 | int r = BIO_read(b: rbio, data: a.data(), dlen: size); |
5419 | if (r <= 0) { |
5420 | a.resize(size: 0); |
5421 | return a; |
5422 | } |
5423 | if (r != size) |
5424 | a.resize(size: r); |
5425 | return a; |
5426 | } |
5427 | |
5428 | Validity peerCertificateValidity() const override |
5429 | { |
5430 | return vr; |
5431 | } |
5432 | |
5433 | CertificateChain peerCertificateChain() const override |
5434 | { |
5435 | // TODO: support whole chain |
5436 | CertificateChain chain; |
5437 | chain.append(t: peercert); |
5438 | return chain; |
5439 | } |
5440 | |
5441 | void doResultsReady() |
5442 | { |
5443 | QMetaObject::invokeMethod(obj: this, member: "resultsReady" , c: Qt::QueuedConnection); |
5444 | } |
5445 | |
5446 | bool init() |
5447 | { |
5448 | context = SSL_CTX_new(meth: method); |
5449 | if (!context) |
5450 | return false; |
5451 | |
5452 | // setup the cert store |
5453 | { |
5454 | X509_STORE *store = SSL_CTX_get_cert_store(context); |
5455 | const QList<Certificate> cert_list = trusted.certificates(); |
5456 | const QList<CRL> crl_list = trusted.crls(); |
5457 | int n; |
5458 | for (n = 0; n < cert_list.count(); ++n) { |
5459 | const MyCertContext *cc = static_cast<const MyCertContext *>(cert_list[n].context()); |
5460 | X509 *x = cc->item.cert; |
5461 | // CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); |
5462 | X509_STORE_add_cert(ctx: store, x); |
5463 | } |
5464 | for (n = 0; n < crl_list.count(); ++n) { |
5465 | const MyCRLContext *cc = static_cast<const MyCRLContext *>(crl_list[n].context()); |
5466 | X509_CRL *x = cc->item.crl; |
5467 | // CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); |
5468 | X509_STORE_add_crl(ctx: store, x); |
5469 | } |
5470 | } |
5471 | |
5472 | ssl = SSL_new(ctx: context); |
5473 | if (!ssl) { |
5474 | SSL_CTX_free(context); |
5475 | context = nullptr; |
5476 | return false; |
5477 | } |
5478 | SSL_set_ssl_method(s: ssl, method); // can this return error? |
5479 | |
5480 | #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME |
5481 | if (targetHostName.isEmpty() == false) { |
5482 | // we have a target |
5483 | // this might fail, but we ignore that for now |
5484 | char *hostname = targetHostName.toLatin1().data(); |
5485 | SSL_set_tlsext_host_name(ssl, hostname); |
5486 | } |
5487 | #endif |
5488 | |
5489 | // setup the memory bio |
5490 | rbio = BIO_new(type: BIO_s_mem()); |
5491 | wbio = BIO_new(type: BIO_s_mem()); |
5492 | |
5493 | // this passes control of the bios to ssl. we don't need to free them. |
5494 | SSL_set_bio(s: ssl, rbio, wbio); |
5495 | |
5496 | // FIXME: move this to after server hello |
5497 | // setup the cert to send |
5498 | if (!cert.isNull() && !key.isNull()) { |
5499 | PrivateKey nkey = key; |
5500 | |
5501 | const PKeyContext *tmp_kc = static_cast<const PKeyContext *>(nkey.context()); |
5502 | |
5503 | if (!tmp_kc->sameProvider(c: this)) { |
5504 | // fprintf(stderr, "experimental: private key supplied by a different provider\n"); |
5505 | |
5506 | // make a pkey pointing to the existing private key |
5507 | EVP_PKEY *pkey; |
5508 | pkey = EVP_PKEY_new(); |
5509 | EVP_PKEY_assign_RSA(pkey, createFromExisting(nkey.toRSA())); |
5510 | |
5511 | // make a new private key object to hold it |
5512 | MyPKeyContext *pk = new MyPKeyContext(provider()); |
5513 | PKeyBase *k = pk->pkeyToBase(pkey, sec: true); // does an EVP_PKEY_free() |
5514 | pk->k = k; |
5515 | nkey.change(c: pk); |
5516 | } |
5517 | |
5518 | const MyCertContext *cc = static_cast<const MyCertContext *>(cert.context()); |
5519 | const MyPKeyContext *kc = static_cast<const MyPKeyContext *>(nkey.context()); |
5520 | |
5521 | if (SSL_use_certificate(ssl, x: cc->item.cert) != 1) { |
5522 | SSL_free(ssl); |
5523 | SSL_CTX_free(context); |
5524 | return false; |
5525 | } |
5526 | if (SSL_use_PrivateKey(ssl, pkey: kc->get_pkey()) != 1) { |
5527 | SSL_free(ssl); |
5528 | SSL_CTX_free(context); |
5529 | return false; |
5530 | } |
5531 | } |
5532 | |
5533 | // request a certificate from the client, if in server mode |
5534 | if (serv) { |
5535 | SSL_set_verify(s: ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, callback: ssl_verify_callback); |
5536 | } |
5537 | |
5538 | return true; |
5539 | } |
5540 | |
5541 | void getCert() |
5542 | { |
5543 | // verify the certificate |
5544 | Validity code = ErrorValidityUnknown; |
5545 | STACK_OF(X509) *x_chain = SSL_get_peer_cert_chain(s: ssl); |
5546 | // X509 *x = SSL_get_peer_certificate(ssl); |
5547 | if (x_chain) { |
5548 | CertificateChain chain; |
5549 | |
5550 | if (serv) { |
5551 | X509 *x = SSL_get_peer_certificate(s: ssl); |
5552 | MyCertContext *cc = new MyCertContext(provider()); |
5553 | cc->fromX509(x); |
5554 | Certificate cert; |
5555 | cert.change(c: cc); |
5556 | chain += cert; |
5557 | } |
5558 | |
5559 | for (int n = 0; n < sk_X509_num(x_chain); ++n) { |
5560 | X509 *x = sk_X509_value(x_chain, n); |
5561 | MyCertContext *cc = new MyCertContext(provider()); |
5562 | cc->fromX509(x); |
5563 | Certificate cert; |
5564 | cert.change(c: cc); |
5565 | chain += cert; |
5566 | } |
5567 | |
5568 | peercert = chain.primary(); |
5569 | |
5570 | #ifdef Q_OS_MAC |
5571 | code = chain.validate(trusted); |
5572 | #else |
5573 | int ret = SSL_get_verify_result(ssl); |
5574 | if (ret == X509_V_OK) |
5575 | code = ValidityGood; |
5576 | else |
5577 | code = convert_verify_error(err: ret); |
5578 | #endif |
5579 | } else { |
5580 | peercert = Certificate(); |
5581 | } |
5582 | vr = code; |
5583 | } |
5584 | |
5585 | int doConnect() |
5586 | { |
5587 | int ret = SSL_connect(ssl); |
5588 | if (ret < 0) { |
5589 | int x = SSL_get_error(s: ssl, ret_code: ret); |
5590 | if (x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) |
5591 | return TryAgain; |
5592 | else |
5593 | return Bad; |
5594 | } else if (ret == 0) |
5595 | return Bad; |
5596 | return Good; |
5597 | } |
5598 | |
5599 | int doAccept() |
5600 | { |
5601 | int ret = SSL_accept(ssl); |
5602 | if (ret < 0) { |
5603 | int x = SSL_get_error(s: ssl, ret_code: ret); |
5604 | if (x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) |
5605 | return TryAgain; |
5606 | else |
5607 | return Bad; |
5608 | } else if (ret == 0) |
5609 | return Bad; |
5610 | return Good; |
5611 | } |
5612 | |
5613 | int doHandshake() |
5614 | { |
5615 | int ret = SSL_do_handshake(s: ssl); |
5616 | if (ret < 0) { |
5617 | int x = SSL_get_error(s: ssl, ret_code: ret); |
5618 | if (x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) |
5619 | return TryAgain; |
5620 | else |
5621 | return Bad; |
5622 | } else if (ret == 0) |
5623 | return Bad; |
5624 | return Good; |
5625 | } |
5626 | |
5627 | int doShutdown() |
5628 | { |
5629 | int ret = SSL_shutdown(s: ssl); |
5630 | if (ret >= 1) |
5631 | return Good; |
5632 | else { |
5633 | if (ret == 0) |
5634 | return TryAgain; |
5635 | int x = SSL_get_error(s: ssl, ret_code: ret); |
5636 | if (x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) |
5637 | return TryAgain; |
5638 | return Bad; |
5639 | } |
5640 | } |
5641 | |
5642 | QByteArray readOutgoing() |
5643 | { |
5644 | QByteArray a; |
5645 | int size = BIO_pending(wbio); |
5646 | if (size <= 0) |
5647 | return a; |
5648 | a.resize(size); |
5649 | |
5650 | int r = BIO_read(b: wbio, data: a.data(), dlen: size); |
5651 | if (r <= 0) { |
5652 | a.resize(size: 0); |
5653 | return a; |
5654 | } |
5655 | if (r != size) |
5656 | a.resize(size: r); |
5657 | return a; |
5658 | } |
5659 | }; |
5660 | |
5661 | class CMSContext : public SMSContext |
5662 | { |
5663 | Q_OBJECT |
5664 | public: |
5665 | CertificateCollection trustedCerts; |
5666 | CertificateCollection untrustedCerts; |
5667 | QList<SecureMessageKey> privateKeys; |
5668 | |
5669 | CMSContext(Provider *p) |
5670 | : SMSContext(p, QStringLiteral("cms" )) |
5671 | { |
5672 | } |
5673 | |
5674 | ~CMSContext() override |
5675 | { |
5676 | } |
5677 | |
5678 | Provider::Context *clone() const override |
5679 | { |
5680 | return nullptr; |
5681 | } |
5682 | |
5683 | void setTrustedCertificates(const CertificateCollection &trusted) override |
5684 | { |
5685 | trustedCerts = trusted; |
5686 | } |
5687 | |
5688 | void setUntrustedCertificates(const CertificateCollection &untrusted) override |
5689 | { |
5690 | untrustedCerts = untrusted; |
5691 | } |
5692 | |
5693 | void setPrivateKeys(const QList<SecureMessageKey> &keys) override |
5694 | { |
5695 | privateKeys = keys; |
5696 | } |
5697 | |
5698 | MessageContext *createMessage() override; |
5699 | }; |
5700 | |
5701 | STACK_OF(X509) * get_pk7_certs(PKCS7 *p7) |
5702 | { |
5703 | int i = OBJ_obj2nid(o: p7->type); |
5704 | if (i == NID_pkcs7_signed) |
5705 | return p7->d.sign->cert; |
5706 | else if (i == NID_pkcs7_signedAndEnveloped) |
5707 | return p7->d.signed_and_enveloped->cert; |
5708 | else |
5709 | return nullptr; |
5710 | } |
5711 | |
5712 | class MyMessageContextThread : public QThread |
5713 | { |
5714 | Q_OBJECT |
5715 | public: |
5716 | SecureMessage::Format format; |
5717 | SecureMessage::SignMode signMode; |
5718 | Certificate cert; |
5719 | PrivateKey key; |
5720 | STACK_OF(X509) * other_certs; |
5721 | BIO *bi; |
5722 | int flags; |
5723 | PKCS7 *p7; |
5724 | bool ok; |
5725 | QByteArray out, sig; |
5726 | |
5727 | MyMessageContextThread(QObject *parent = nullptr) |
5728 | : QThread(parent) |
5729 | , ok(false) |
5730 | { |
5731 | } |
5732 | |
5733 | protected: |
5734 | void run() override |
5735 | { |
5736 | MyCertContext *cc = static_cast<MyCertContext *>(cert.context()); |
5737 | MyPKeyContext *kc = static_cast<MyPKeyContext *>(key.context()); |
5738 | X509 *cx = cc->item.cert; |
5739 | EVP_PKEY *kx = kc->get_pkey(); |
5740 | |
5741 | p7 = PKCS7_sign(signcert: cx, pkey: kx, certs: other_certs, data: bi, flags); |
5742 | |
5743 | BIO_free(a: bi); |
5744 | sk_X509_pop_free(other_certs, X509_free); |
5745 | |
5746 | if (p7) { |
5747 | // printf("good\n"); |
5748 | BIO *bo; |
5749 | |
5750 | // BIO *bo = BIO_new(BIO_s_mem()); |
5751 | // i2d_PKCS7_bio(bo, p7); |
5752 | // PEM_write_bio_PKCS7(bo, p7); |
5753 | // SecureArray buf = bio2buf(bo); |
5754 | // printf("[%s]\n", buf.data()); |
5755 | |
5756 | bo = BIO_new(type: BIO_s_mem()); |
5757 | if (format == SecureMessage::Binary) |
5758 | i2d_PKCS7_bio(bp: bo, p7); |
5759 | else // Ascii |
5760 | PEM_write_bio_PKCS7(out: bo, x: p7); |
5761 | |
5762 | if (SecureMessage::Detached == signMode) |
5763 | sig = bio2ba(b: bo); |
5764 | else |
5765 | out = bio2ba(b: bo); |
5766 | |
5767 | ok = true; |
5768 | } else { |
5769 | printf(format: "bad here\n" ); |
5770 | ERR_print_errors_fp(stdout); |
5771 | } |
5772 | } |
5773 | }; |
5774 | |
5775 | class MyMessageContext : public MessageContext |
5776 | { |
5777 | Q_OBJECT |
5778 | public: |
5779 | CMSContext *cms; |
5780 | SecureMessageKey signer; |
5781 | SecureMessageKeyList to; |
5782 | SecureMessage::SignMode signMode; |
5783 | bool bundleSigner; |
5784 | bool smime; |
5785 | SecureMessage::Format format; |
5786 | |
5787 | Operation op; |
5788 | bool _finished; |
5789 | |
5790 | QByteArray in, out; |
5791 | QByteArray sig; |
5792 | int total; |
5793 | |
5794 | CertificateChain signerChain; |
5795 | int ver_ret; |
5796 | |
5797 | MyMessageContextThread *thread; |
5798 | |
5799 | MyMessageContext(CMSContext *_cms, Provider *p) |
5800 | : MessageContext(p, QStringLiteral("cmsmsg" )) |
5801 | { |
5802 | cms = _cms; |
5803 | |
5804 | total = 0; |
5805 | |
5806 | ver_ret = 0; |
5807 | |
5808 | thread = nullptr; |
5809 | } |
5810 | |
5811 | ~MyMessageContext() override |
5812 | { |
5813 | } |
5814 | |
5815 | Provider::Context *clone() const override |
5816 | { |
5817 | return nullptr; |
5818 | } |
5819 | |
5820 | bool canSignMultiple() const override |
5821 | { |
5822 | return false; |
5823 | } |
5824 | |
5825 | SecureMessage::Type type() const override |
5826 | { |
5827 | return SecureMessage::CMS; |
5828 | } |
5829 | |
5830 | void reset() override |
5831 | { |
5832 | } |
5833 | |
5834 | void setupEncrypt(const SecureMessageKeyList &keys) override |
5835 | { |
5836 | to = keys; |
5837 | } |
5838 | |
5839 | void setupSign(const SecureMessageKeyList &keys, SecureMessage::SignMode m, bool bundleSigner, bool smime) override |
5840 | { |
5841 | signer = keys.first(); |
5842 | signMode = m; |
5843 | this->bundleSigner = bundleSigner; |
5844 | this->smime = smime; |
5845 | } |
5846 | |
5847 | void setupVerify(const QByteArray &detachedSig) override |
5848 | { |
5849 | // TODO |
5850 | sig = detachedSig; |
5851 | } |
5852 | |
5853 | void start(SecureMessage::Format f, Operation op) override |
5854 | { |
5855 | format = f; |
5856 | _finished = false; |
5857 | |
5858 | // TODO: other operations |
5859 | // if(op == Sign) |
5860 | //{ |
5861 | this->op = op; |
5862 | //} |
5863 | // else if(op == Encrypt) |
5864 | //{ |
5865 | // this->op = op; |
5866 | //} |
5867 | } |
5868 | |
5869 | void update(const QByteArray &in) override |
5870 | { |
5871 | this->in.append(a: in); |
5872 | total += in.size(); |
5873 | QMetaObject::invokeMethod(obj: this, member: "updated" , c: Qt::QueuedConnection); |
5874 | } |
5875 | |
5876 | QByteArray read() override |
5877 | { |
5878 | return out; |
5879 | } |
5880 | |
5881 | int written() override |
5882 | { |
5883 | int x = total; |
5884 | total = 0; |
5885 | return x; |
5886 | } |
5887 | |
5888 | void end() override |
5889 | { |
5890 | _finished = true; |
5891 | |
5892 | // sign |
5893 | if (op == Sign) { |
5894 | const CertificateChain chain = signer.x509CertificateChain(); |
5895 | Certificate cert = chain.primary(); |
5896 | QList<Certificate> nonroots; |
5897 | if (chain.count() > 1) { |
5898 | for (int n = 1; n < chain.count(); ++n) |
5899 | nonroots.append(t: chain[n]); |
5900 | } |
5901 | PrivateKey key = signer.x509PrivateKey(); |
5902 | |
5903 | const PKeyContext *tmp_kc = static_cast<const PKeyContext *>(key.context()); |
5904 | |
5905 | if (!tmp_kc->sameProvider(c: this)) { |
5906 | // fprintf(stderr, "experimental: private key supplied by a different provider\n"); |
5907 | |
5908 | // make a pkey pointing to the existing private key |
5909 | EVP_PKEY *pkey; |
5910 | pkey = EVP_PKEY_new(); |
5911 | EVP_PKEY_assign_RSA(pkey, createFromExisting(key.toRSA())); |
5912 | |
5913 | // make a new private key object to hold it |
5914 | MyPKeyContext *pk = new MyPKeyContext(provider()); |
5915 | PKeyBase *k = pk->pkeyToBase(pkey, sec: true); // does an EVP_PKEY_free() |
5916 | pk->k = k; |
5917 | key.change(c: pk); |
5918 | } |
5919 | |
5920 | // allow different cert provider. this is just a |
5921 | // quick hack, enough to please qca-test |
5922 | if (!cert.context()->sameProvider(c: this)) { |
5923 | // fprintf(stderr, "experimental: cert supplied by a different provider\n"); |
5924 | cert = Certificate::fromDER(a: cert.toDER()); |
5925 | if (cert.isNull() || !cert.context()->sameProvider(c: this)) { |
5926 | // fprintf(stderr, "error converting cert\n"); |
5927 | } |
5928 | } |
5929 | |
5930 | // MyCertContext *cc = static_cast<MyCertContext *>(cert.context()); |
5931 | // MyPKeyContext *kc = static_cast<MyPKeyContext *>(key.context()); |
5932 | |
5933 | // X509 *cx = cc->item.cert; |
5934 | // EVP_PKEY *kx = kc->get_pkey(); |
5935 | |
5936 | STACK_OF(X509) * other_certs; |
5937 | BIO *bi; |
5938 | int flags; |
5939 | // PKCS7 *p7; |
5940 | |
5941 | // nonroots |
5942 | other_certs = sk_X509_new_null(); |
5943 | for (int n = 0; n < nonroots.count(); ++n) { |
5944 | X509 *x = static_cast<MyCertContext *>(nonroots[n].context())->item.cert; |
5945 | X509_up_ref(x); |
5946 | sk_X509_push(other_certs, x); |
5947 | } |
5948 | |
5949 | // printf("bundling %d other_certs\n", sk_X509_num(other_certs)); |
5950 | |
5951 | bi = BIO_new(type: BIO_s_mem()); |
5952 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
5953 | |
5954 | flags = 0; |
5955 | flags |= PKCS7_BINARY; |
5956 | if (SecureMessage::Detached == signMode) { |
5957 | flags |= PKCS7_DETACHED; |
5958 | } |
5959 | if (false == bundleSigner) |
5960 | flags |= PKCS7_NOCERTS; |
5961 | |
5962 | if (thread) |
5963 | delete thread; |
5964 | thread = new MyMessageContextThread(this); |
5965 | thread->format = format; |
5966 | thread->signMode = signMode; |
5967 | thread->cert = cert; |
5968 | thread->key = key; |
5969 | thread->other_certs = other_certs; |
5970 | thread->bi = bi; |
5971 | thread->flags = flags; |
5972 | connect(sender: thread, signal: &MyMessageContextThread::finished, context: this, slot: &MyMessageContext::thread_finished); |
5973 | thread->start(); |
5974 | } else if (op == Encrypt) { |
5975 | // TODO: support multiple recipients |
5976 | Certificate target = to.first().x509CertificateChain().primary(); |
5977 | |
5978 | STACK_OF(X509) * other_certs; |
5979 | BIO *bi; |
5980 | int flags; |
5981 | PKCS7 *p7; |
5982 | |
5983 | other_certs = sk_X509_new_null(); |
5984 | X509 *x = static_cast<MyCertContext *>(target.context())->item.cert; |
5985 | X509_up_ref(x); |
5986 | sk_X509_push(other_certs, x); |
5987 | |
5988 | bi = BIO_new(type: BIO_s_mem()); |
5989 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
5990 | |
5991 | flags = 0; |
5992 | flags |= PKCS7_BINARY; |
5993 | p7 = PKCS7_encrypt(certs: other_certs, in: bi, cipher: EVP_des_ede3_cbc(), flags); // TODO: cipher? |
5994 | |
5995 | BIO_free(a: bi); |
5996 | sk_X509_pop_free(other_certs, X509_free); |
5997 | |
5998 | if (p7) { |
5999 | // FIXME: format |
6000 | BIO *bo = BIO_new(type: BIO_s_mem()); |
6001 | i2d_PKCS7_bio(bp: bo, p7); |
6002 | // PEM_write_bio_PKCS7(bo, p7); |
6003 | out = bio2ba(b: bo); |
6004 | PKCS7_free(a: p7); |
6005 | } else { |
6006 | printf(format: "bad\n" ); |
6007 | return; |
6008 | } |
6009 | } else if (op == Verify) { |
6010 | // TODO: support non-detached sigs |
6011 | |
6012 | BIO *out = BIO_new(type: BIO_s_mem()); |
6013 | BIO *bi = BIO_new(type: BIO_s_mem()); |
6014 | if (false == sig.isEmpty()) { |
6015 | // We have detached signature |
6016 | BIO_write(b: bi, data: sig.data(), dlen: sig.size()); |
6017 | } else { |
6018 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
6019 | } |
6020 | PKCS7 *p7; |
6021 | if (format == SecureMessage::Binary) |
6022 | p7 = d2i_PKCS7_bio(bp: bi, p7: nullptr); |
6023 | else // Ascii |
6024 | p7 = PEM_read_bio_PKCS7(out: bi, x: nullptr, cb: passphrase_cb, u: nullptr); |
6025 | BIO_free(a: bi); |
6026 | |
6027 | if (!p7) { |
6028 | // TODO |
6029 | printf(format: "bad1\n" ); |
6030 | QMetaObject::invokeMethod(obj: this, member: "updated" , c: Qt::QueuedConnection); |
6031 | return; |
6032 | } |
6033 | |
6034 | // intermediates/signers that may not be in the blob |
6035 | STACK_OF(X509) *other_certs = sk_X509_new_null(); |
6036 | QList<Certificate> untrusted_list = cms->untrustedCerts.certificates(); |
6037 | const QList<CRL> untrusted_crls = cms->untrustedCerts.crls(); // we'll use the crls later |
6038 | for (int n = 0; n < untrusted_list.count(); ++n) { |
6039 | X509 *x = static_cast<MyCertContext *>(untrusted_list[n].context())->item.cert; |
6040 | X509_up_ref(x); |
6041 | sk_X509_push(other_certs, x); |
6042 | } |
6043 | |
6044 | // get the possible message signers |
6045 | QList<Certificate> signers; |
6046 | STACK_OF(X509) *xs = PKCS7_get0_signers(p7, certs: other_certs, flags: 0); |
6047 | if (xs) { |
6048 | for (int n = 0; n < sk_X509_num(xs); ++n) { |
6049 | MyCertContext *cc = new MyCertContext(provider()); |
6050 | cc->fromX509(sk_X509_value(xs, n)); |
6051 | Certificate cert; |
6052 | cert.change(c: cc); |
6053 | // printf("signer: [%s]\n", qPrintable(cert.commonName())); |
6054 | signers.append(t: cert); |
6055 | } |
6056 | sk_X509_free(xs); |
6057 | } |
6058 | |
6059 | // get the rest of the certificates lying around |
6060 | QList<Certificate> others; |
6061 | xs = get_pk7_certs(p7); // don't free |
6062 | if (xs) { |
6063 | for (int n = 0; n < sk_X509_num(xs); ++n) { |
6064 | MyCertContext *cc = new MyCertContext(provider()); |
6065 | cc->fromX509(sk_X509_value(xs, n)); |
6066 | Certificate cert; |
6067 | cert.change(c: cc); |
6068 | others.append(t: cert); |
6069 | // printf("other: [%s]\n", qPrintable(cert.commonName())); |
6070 | } |
6071 | } |
6072 | |
6073 | // signer needs to be supplied in the message itself |
6074 | // or via cms->untrustedCerts |
6075 | if (signers.isEmpty()) { |
6076 | QMetaObject::invokeMethod(obj: this, member: "updated" , c: Qt::QueuedConnection); |
6077 | return; |
6078 | } |
6079 | |
6080 | // FIXME: handle more than one signer |
6081 | CertificateChain chain; |
6082 | chain += signers[0]; |
6083 | |
6084 | // build chain |
6085 | chain = chain.complete(issuers: others); |
6086 | |
6087 | signerChain = chain; |
6088 | |
6089 | X509_STORE *store = X509_STORE_new(); |
6090 | const QList<Certificate> cert_list = cms->trustedCerts.certificates(); |
6091 | QList<CRL> crl_list = cms->trustedCerts.crls(); |
6092 | for (int n = 0; n < cert_list.count(); ++n) { |
6093 | // printf("trusted: [%s]\n", qPrintable(cert_list[n].commonName())); |
6094 | const MyCertContext *cc = static_cast<const MyCertContext *>(cert_list[n].context()); |
6095 | X509 *x = cc->item.cert; |
6096 | // CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); |
6097 | X509_STORE_add_cert(ctx: store, x); |
6098 | } |
6099 | for (int n = 0; n < crl_list.count(); ++n) { |
6100 | const MyCRLContext *cc = static_cast<const MyCRLContext *>(crl_list[n].context()); |
6101 | X509_CRL *x = cc->item.crl; |
6102 | // CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); |
6103 | X509_STORE_add_crl(ctx: store, x); |
6104 | } |
6105 | // add these crls also |
6106 | crl_list = untrusted_crls; |
6107 | for (int n = 0; n < crl_list.count(); ++n) { |
6108 | const MyCRLContext *cc = static_cast<const MyCRLContext *>(crl_list[n].context()); |
6109 | X509_CRL *x = cc->item.crl; |
6110 | // CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); |
6111 | X509_STORE_add_crl(ctx: store, x); |
6112 | } |
6113 | |
6114 | int ret; |
6115 | if (!sig.isEmpty()) { |
6116 | // Detached signMode |
6117 | bi = BIO_new(type: BIO_s_mem()); |
6118 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
6119 | ret = PKCS7_verify(p7, certs: other_certs, store, indata: bi, out: nullptr, flags: 0); |
6120 | BIO_free(a: bi); |
6121 | } else { |
6122 | ret = PKCS7_verify(p7, certs: other_certs, store, indata: nullptr, out, flags: 0); |
6123 | // qDebug() << "Verify: " << ret; |
6124 | } |
6125 | // if(!ret) |
6126 | // ERR_print_errors_fp(stdout); |
6127 | sk_X509_pop_free(other_certs, X509_free); |
6128 | X509_STORE_free(v: store); |
6129 | PKCS7_free(a: p7); |
6130 | |
6131 | ver_ret = ret; |
6132 | // TODO |
6133 | |
6134 | QMetaObject::invokeMethod(obj: this, member: "updated" , c: Qt::QueuedConnection); |
6135 | } else if (op == Decrypt) { |
6136 | bool ok = false; |
6137 | for (int n = 0; n < cms->privateKeys.count(); ++n) { |
6138 | CertificateChain chain = cms->privateKeys[n].x509CertificateChain(); |
6139 | Certificate cert = chain.primary(); |
6140 | PrivateKey key = cms->privateKeys[n].x509PrivateKey(); |
6141 | |
6142 | MyCertContext *cc = static_cast<MyCertContext *>(cert.context()); |
6143 | MyPKeyContext *kc = static_cast<MyPKeyContext *>(key.context()); |
6144 | |
6145 | X509 *cx = cc->item.cert; |
6146 | EVP_PKEY *kx = kc->get_pkey(); |
6147 | |
6148 | BIO *bi = BIO_new(type: BIO_s_mem()); |
6149 | BIO_write(b: bi, data: in.data(), dlen: in.size()); |
6150 | PKCS7 *p7 = d2i_PKCS7_bio(bp: bi, p7: nullptr); |
6151 | BIO_free(a: bi); |
6152 | |
6153 | if (!p7) { |
6154 | // TODO |
6155 | printf(format: "bad1\n" ); |
6156 | return; |
6157 | } |
6158 | |
6159 | BIO *bo = BIO_new(type: BIO_s_mem()); |
6160 | int ret = PKCS7_decrypt(p7, pkey: kx, cert: cx, data: bo, flags: 0); |
6161 | PKCS7_free(a: p7); |
6162 | if (!ret) |
6163 | continue; |
6164 | |
6165 | ok = true; |
6166 | out = bio2ba(b: bo); |
6167 | break; |
6168 | } |
6169 | |
6170 | if (!ok) { |
6171 | // TODO |
6172 | printf(format: "bad2\n" ); |
6173 | return; |
6174 | } |
6175 | } |
6176 | } |
6177 | |
6178 | bool finished() const override |
6179 | { |
6180 | return _finished; |
6181 | } |
6182 | |
6183 | bool waitForFinished(int msecs) override |
6184 | { |
6185 | // TODO |
6186 | Q_UNUSED(msecs); |
6187 | |
6188 | if (thread) { |
6189 | thread->wait(); |
6190 | getresults(); |
6191 | } |
6192 | return true; |
6193 | } |
6194 | |
6195 | bool success() const override |
6196 | { |
6197 | // TODO |
6198 | return true; |
6199 | } |
6200 | |
6201 | SecureMessage::Error errorCode() const override |
6202 | { |
6203 | // TODO |
6204 | return SecureMessage::ErrorUnknown; |
6205 | } |
6206 | |
6207 | QByteArray signature() const override |
6208 | { |
6209 | return sig; |
6210 | } |
6211 | |
6212 | QString hashName() const override |
6213 | { |
6214 | // TODO |
6215 | return QStringLiteral("sha1" ); |
6216 | } |
6217 | |
6218 | SecureMessageSignatureList signers() const override |
6219 | { |
6220 | // only report signers for verify |
6221 | if (op != Verify) |
6222 | return SecureMessageSignatureList(); |
6223 | |
6224 | SecureMessageKey key; |
6225 | if (!signerChain.isEmpty()) |
6226 | key.setX509CertificateChain(signerChain); |
6227 | |
6228 | // TODO/FIXME !!! InvalidSignature might be used here even |
6229 | // if the signature is just fine, and the key is invalid |
6230 | // (we need to use InvalidKey instead). |
6231 | |
6232 | Validity vr = ErrorValidityUnknown; |
6233 | if (!signerChain.isEmpty()) |
6234 | vr = signerChain.validate(trusted: cms->trustedCerts, untrusted_crls: cms->untrustedCerts.crls()); |
6235 | |
6236 | SecureMessageSignature::IdentityResult ir; |
6237 | if (vr == ValidityGood) |
6238 | ir = SecureMessageSignature::Valid; |
6239 | else |
6240 | ir = SecureMessageSignature::InvalidKey; |
6241 | |
6242 | if (!ver_ret) |
6243 | ir = SecureMessageSignature::InvalidSignature; |
6244 | |
6245 | SecureMessageSignature s(ir, vr, key, QDateTime::currentDateTime()); |
6246 | |
6247 | // TODO |
6248 | return SecureMessageSignatureList() << s; |
6249 | } |
6250 | |
6251 | void getresults() |
6252 | { |
6253 | sig = thread->sig; |
6254 | out = thread->out; |
6255 | } |
6256 | |
6257 | private Q_SLOTS: |
6258 | void thread_finished() |
6259 | { |
6260 | getresults(); |
6261 | emit updated(); |
6262 | } |
6263 | }; |
6264 | |
6265 | MessageContext *CMSContext::createMessage() |
6266 | { |
6267 | return new MyMessageContext(this, provider()); |
6268 | } |
6269 | |
6270 | class opensslCipherContext : public CipherContext |
6271 | { |
6272 | Q_OBJECT |
6273 | public: |
6274 | opensslCipherContext(const EVP_CIPHER *algorithm, const int pad, Provider *p, const QString &type) |
6275 | : CipherContext(p, type) |
6276 | { |
6277 | m_cryptoAlgorithm = algorithm; |
6278 | m_context = EVP_CIPHER_CTX_new(); |
6279 | EVP_CIPHER_CTX_init(m_context); |
6280 | m_pad = pad; |
6281 | m_type = type; |
6282 | } |
6283 | |
6284 | opensslCipherContext(const opensslCipherContext &other) |
6285 | : CipherContext(other) |
6286 | { |
6287 | m_cryptoAlgorithm = other.m_cryptoAlgorithm; |
6288 | m_context = EVP_CIPHER_CTX_new(); |
6289 | EVP_CIPHER_CTX_copy(out: m_context, in: other.m_context); |
6290 | m_direction = other.m_direction; |
6291 | m_pad = other.m_pad; |
6292 | m_type = other.m_type; |
6293 | m_tag = other.m_tag; |
6294 | } |
6295 | |
6296 | ~opensslCipherContext() override |
6297 | { |
6298 | EVP_CIPHER_CTX_cleanup(m_context); |
6299 | EVP_CIPHER_CTX_free(c: m_context); |
6300 | } |
6301 | |
6302 | void setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv, const AuthTag &tag) override |
6303 | { |
6304 | m_tag = tag; |
6305 | m_direction = dir; |
6306 | if ((m_cryptoAlgorithm == EVP_des_ede3()) && (key.size() == 16)) { |
6307 | // this is really a two key version of triple DES. |
6308 | m_cryptoAlgorithm = EVP_des_ede(); |
6309 | } |
6310 | if (Encode == m_direction) { |
6311 | EVP_EncryptInit_ex(ctx: m_context, cipher: m_cryptoAlgorithm, impl: nullptr, key: nullptr, iv: nullptr); |
6312 | EVP_CIPHER_CTX_set_key_length(x: m_context, keylen: key.size()); |
6313 | if (m_type.endsWith(s: QLatin1String("gcm" )) || m_type.endsWith(s: QLatin1String("ccm" ))) { |
6314 | int parameter = m_type.endsWith(s: QLatin1String("gcm" )) ? EVP_CTRL_GCM_SET_IVLEN : EVP_CTRL_CCM_SET_IVLEN; |
6315 | EVP_CIPHER_CTX_ctrl(ctx: m_context, type: parameter, arg: iv.size(), ptr: nullptr); |
6316 | } |
6317 | EVP_EncryptInit_ex( |
6318 | ctx: m_context, cipher: nullptr, impl: nullptr, key: (const unsigned char *)(key.data()), iv: (const unsigned char *)(iv.data())); |
6319 | } else { |
6320 | EVP_DecryptInit_ex(ctx: m_context, cipher: m_cryptoAlgorithm, impl: nullptr, key: nullptr, iv: nullptr); |
6321 | EVP_CIPHER_CTX_set_key_length(x: m_context, keylen: key.size()); |
6322 | if (m_type.endsWith(s: QLatin1String("gcm" )) || m_type.endsWith(s: QLatin1String("ccm" ))) { |
6323 | int parameter = m_type.endsWith(s: QLatin1String("gcm" )) ? EVP_CTRL_GCM_SET_IVLEN : EVP_CTRL_CCM_SET_IVLEN; |
6324 | EVP_CIPHER_CTX_ctrl(ctx: m_context, type: parameter, arg: iv.size(), ptr: nullptr); |
6325 | } |
6326 | EVP_DecryptInit_ex( |
6327 | ctx: m_context, cipher: nullptr, impl: nullptr, key: (const unsigned char *)(key.data()), iv: (const unsigned char *)(iv.data())); |
6328 | } |
6329 | |
6330 | EVP_CIPHER_CTX_set_padding(c: m_context, pad: m_pad); |
6331 | } |
6332 | |
6333 | Provider::Context *clone() const override |
6334 | { |
6335 | return new opensslCipherContext(*this); |
6336 | } |
6337 | |
6338 | int blockSize() const override |
6339 | { |
6340 | return EVP_CIPHER_CTX_block_size(ctx: m_context); |
6341 | } |
6342 | |
6343 | AuthTag tag() const override |
6344 | { |
6345 | return m_tag; |
6346 | } |
6347 | |
6348 | bool update(const SecureArray &in, SecureArray *out) override |
6349 | { |
6350 | // This works around a problem in OpenSSL, where it asserts if |
6351 | // there is nothing to encrypt. |
6352 | if (0 == in.size()) |
6353 | return true; |
6354 | |
6355 | out->resize(size: in.size() + blockSize()); |
6356 | int resultLength; |
6357 | if (Encode == m_direction) { |
6358 | if (0 == |
6359 | EVP_EncryptUpdate( |
6360 | ctx: m_context, out: (unsigned char *)out->data(), outl: &resultLength, in: (unsigned char *)in.data(), inl: in.size())) { |
6361 | return false; |
6362 | } |
6363 | } else { |
6364 | if (0 == |
6365 | EVP_DecryptUpdate( |
6366 | ctx: m_context, out: (unsigned char *)out->data(), outl: &resultLength, in: (unsigned char *)in.data(), inl: in.size())) { |
6367 | return false; |
6368 | } |
6369 | } |
6370 | out->resize(size: resultLength); |
6371 | return true; |
6372 | } |
6373 | |
6374 | bool final(SecureArray *out) override |
6375 | { |
6376 | out->resize(size: blockSize()); |
6377 | int resultLength; |
6378 | if (Encode == m_direction) { |
6379 | if (0 == EVP_EncryptFinal_ex(ctx: m_context, out: (unsigned char *)out->data(), outl: &resultLength)) { |
6380 | return false; |
6381 | } |
6382 | if (m_tag.size() && (m_type.endsWith(s: QLatin1String("gcm" )) || m_type.endsWith(s: QLatin1String("ccm" )))) { |
6383 | int parameter = m_type.endsWith(s: QLatin1String("gcm" )) ? EVP_CTRL_GCM_GET_TAG : EVP_CTRL_CCM_GET_TAG; |
6384 | if (0 == EVP_CIPHER_CTX_ctrl(ctx: m_context, type: parameter, arg: m_tag.size(), ptr: (unsigned char *)m_tag.data())) { |
6385 | return false; |
6386 | } |
6387 | } |
6388 | } else { |
6389 | if (m_tag.size() && (m_type.endsWith(s: QLatin1String("gcm" )) || m_type.endsWith(s: QLatin1String("ccm" )))) { |
6390 | int parameter = m_type.endsWith(s: QLatin1String("gcm" )) ? EVP_CTRL_GCM_SET_TAG : EVP_CTRL_CCM_SET_TAG; |
6391 | if (0 == EVP_CIPHER_CTX_ctrl(ctx: m_context, type: parameter, arg: m_tag.size(), ptr: m_tag.data())) { |
6392 | return false; |
6393 | } |
6394 | } |
6395 | if (0 == EVP_DecryptFinal_ex(ctx: m_context, outm: (unsigned char *)out->data(), outl: &resultLength)) { |
6396 | return false; |
6397 | } |
6398 | } |
6399 | out->resize(size: resultLength); |
6400 | return true; |
6401 | } |
6402 | |
6403 | // Change cipher names |
6404 | KeyLength keyLength() const override |
6405 | { |
6406 | if (s_legacyProviderAvailable) { |
6407 | if (m_type.left(n: 4) == QLatin1String("des-" )) { |
6408 | return KeyLength(8, 8, 1); |
6409 | } else if (m_type.left(n: 5) == QLatin1String("cast5" )) { |
6410 | return KeyLength(5, 16, 1); |
6411 | } else if (m_type.left(n: 8) == QLatin1String("blowfish" )) { |
6412 | // Don't know - TODO |
6413 | return KeyLength(1, 32, 1); |
6414 | } |
6415 | } |
6416 | if (m_type.left(n: 6) == QLatin1String("aes128" )) { |
6417 | return KeyLength(16, 16, 1); |
6418 | } else if (m_type.left(n: 6) == QLatin1String("aes192" )) { |
6419 | return KeyLength(24, 24, 1); |
6420 | } else if (m_type.left(n: 6) == QLatin1String("aes256" )) { |
6421 | return KeyLength(32, 32, 1); |
6422 | } else if (m_type.left(n: 9) == QLatin1String("tripledes" )) { |
6423 | return KeyLength(16, 24, 1); |
6424 | } |
6425 | return KeyLength(0, 1, 1); |
6426 | } |
6427 | |
6428 | protected: |
6429 | EVP_CIPHER_CTX *m_context; |
6430 | const EVP_CIPHER *m_cryptoAlgorithm; |
6431 | Direction m_direction; |
6432 | int m_pad; |
6433 | QString m_type; |
6434 | AuthTag m_tag; |
6435 | }; |
6436 | |
6437 | static QStringList all_hash_types() |
6438 | { |
6439 | QStringList list; |
6440 | list += QStringLiteral("sha1" ); |
6441 | #ifdef HAVE_OPENSSL_SHA0 |
6442 | list += QStringLiteral("sha0" ); |
6443 | #endif |
6444 | list += QStringLiteral("md5" ); |
6445 | #ifdef SHA224_DIGEST_LENGTH |
6446 | list += QStringLiteral("sha224" ); |
6447 | #endif |
6448 | #ifdef SHA256_DIGEST_LENGTH |
6449 | list += QStringLiteral("sha256" ); |
6450 | #endif |
6451 | #ifdef SHA384_DIGEST_LENGTH |
6452 | list += QStringLiteral("sha384" ); |
6453 | #endif |
6454 | #ifdef SHA512_DIGEST_LENGTH |
6455 | list += QStringLiteral("sha512" ); |
6456 | #endif |
6457 | if (s_legacyProviderAvailable) { |
6458 | list += QStringLiteral("ripemd160" ); |
6459 | #ifdef HAVE_OPENSSL_MD2 |
6460 | list += QStringLiteral("md2" ); |
6461 | #endif |
6462 | list += QStringLiteral("md4" ); |
6463 | #ifdef OBJ_whirlpool |
6464 | list += QStringLiteral("whirlpool" ); |
6465 | #endif |
6466 | } |
6467 | |
6468 | return list; |
6469 | } |
6470 | |
6471 | static QStringList all_cipher_types() |
6472 | { |
6473 | QStringList list; |
6474 | list += QStringLiteral("aes128-ecb" ); |
6475 | list += QStringLiteral("aes128-cfb" ); |
6476 | list += QStringLiteral("aes128-cbc" ); |
6477 | list += QStringLiteral("aes128-cbc-pkcs7" ); |
6478 | list += QStringLiteral("aes128-ofb" ); |
6479 | #ifdef HAVE_OPENSSL_AES_CTR |
6480 | list += QStringLiteral("aes128-ctr" ); |
6481 | #endif |
6482 | #ifdef HAVE_OPENSSL_AES_GCM |
6483 | list += QStringLiteral("aes128-gcm" ); |
6484 | #endif |
6485 | #ifdef HAVE_OPENSSL_AES_CCM |
6486 | list += QStringLiteral("aes128-ccm" ); |
6487 | #endif |
6488 | list += QStringLiteral("aes192-ecb" ); |
6489 | list += QStringLiteral("aes192-cfb" ); |
6490 | list += QStringLiteral("aes192-cbc" ); |
6491 | list += QStringLiteral("aes192-cbc-pkcs7" ); |
6492 | list += QStringLiteral("aes192-ofb" ); |
6493 | #ifdef HAVE_OPENSSL_AES_CTR |
6494 | list += QStringLiteral("aes192-ctr" ); |
6495 | #endif |
6496 | #ifdef HAVE_OPENSSL_AES_GCM |
6497 | list += QStringLiteral("aes192-gcm" ); |
6498 | #endif |
6499 | #ifdef HAVE_OPENSSL_AES_CCM |
6500 | list += QStringLiteral("aes192-ccm" ); |
6501 | #endif |
6502 | list += QStringLiteral("aes256-ecb" ); |
6503 | list += QStringLiteral("aes256-cbc" ); |
6504 | list += QStringLiteral("aes256-cbc-pkcs7" ); |
6505 | list += QStringLiteral("aes256-cfb" ); |
6506 | list += QStringLiteral("aes256-ofb" ); |
6507 | #ifdef HAVE_OPENSSL_AES_CTR |
6508 | list += QStringLiteral("aes256-ctr" ); |
6509 | #endif |
6510 | #ifdef HAVE_OPENSSL_AES_GCM |
6511 | list += QStringLiteral("aes256-gcm" ); |
6512 | #endif |
6513 | #ifdef HAVE_OPENSSL_AES_CCM |
6514 | list += QStringLiteral("aes256-ccm" ); |
6515 | #endif |
6516 | list += QStringLiteral("tripledes-ecb" ); |
6517 | list += QStringLiteral("tripledes-cbc" ); |
6518 | if (s_legacyProviderAvailable) { |
6519 | list += QStringLiteral("blowfish-ecb" ); |
6520 | list += QStringLiteral("blowfish-cbc-pkcs7" ); |
6521 | list += QStringLiteral("blowfish-cbc" ); |
6522 | list += QStringLiteral("blowfish-cfb" ); |
6523 | list += QStringLiteral("blowfish-ofb" ); |
6524 | list += QStringLiteral("des-ecb" ); |
6525 | list += QStringLiteral("des-ecb-pkcs7" ); |
6526 | list += QStringLiteral("des-cbc" ); |
6527 | list += QStringLiteral("des-cbc-pkcs7" ); |
6528 | list += QStringLiteral("des-cfb" ); |
6529 | list += QStringLiteral("des-ofb" ); |
6530 | #ifndef OPENSSL_NO_CAST |
6531 | list += QStringLiteral("cast5-ecb" ); |
6532 | list += QStringLiteral("cast5-cbc" ); |
6533 | list += QStringLiteral("cast5-cbc-pkcs7" ); |
6534 | list += QStringLiteral("cast5-cfb" ); |
6535 | list += QStringLiteral("cast5-ofb" ); |
6536 | #endif |
6537 | } |
6538 | return list; |
6539 | } |
6540 | |
6541 | static QStringList all_mac_types() |
6542 | { |
6543 | QStringList list; |
6544 | list += QStringLiteral("hmac(md5)" ); |
6545 | list += QStringLiteral("hmac(sha1)" ); |
6546 | #ifdef SHA224_DIGEST_LENGTH |
6547 | list += QStringLiteral("hmac(sha224)" ); |
6548 | #endif |
6549 | #ifdef SHA256_DIGEST_LENGTH |
6550 | list += QStringLiteral("hmac(sha256)" ); |
6551 | #endif |
6552 | #ifdef SHA384_DIGEST_LENGTH |
6553 | list += QStringLiteral("hmac(sha384)" ); |
6554 | #endif |
6555 | #ifdef SHA512_DIGEST_LENGTH |
6556 | list += QStringLiteral("hmac(sha512)" ); |
6557 | #endif |
6558 | if (s_legacyProviderAvailable) { |
6559 | list += QStringLiteral("hmac(ripemd160)" ); |
6560 | } |
6561 | return list; |
6562 | } |
6563 | |
6564 | class opensslInfoContext : public InfoContext |
6565 | { |
6566 | Q_OBJECT |
6567 | public: |
6568 | opensslInfoContext(Provider *p) |
6569 | : InfoContext(p) |
6570 | { |
6571 | } |
6572 | |
6573 | Provider::Context *clone() const override |
6574 | { |
6575 | return new opensslInfoContext(*this); |
6576 | } |
6577 | |
6578 | QStringList supportedHashTypes() const override |
6579 | { |
6580 | return all_hash_types(); |
6581 | } |
6582 | |
6583 | QStringList supportedCipherTypes() const override |
6584 | { |
6585 | return all_cipher_types(); |
6586 | } |
6587 | |
6588 | QStringList supportedMACTypes() const override |
6589 | { |
6590 | return all_mac_types(); |
6591 | } |
6592 | }; |
6593 | |
6594 | class opensslRandomContext : public RandomContext |
6595 | { |
6596 | Q_OBJECT |
6597 | public: |
6598 | opensslRandomContext(QCA::Provider *p) |
6599 | : RandomContext(p) |
6600 | { |
6601 | } |
6602 | |
6603 | Context *clone() const override |
6604 | { |
6605 | return new opensslRandomContext(*this); |
6606 | } |
6607 | |
6608 | QCA::SecureArray nextBytes(int size) override |
6609 | { |
6610 | QCA::SecureArray buf(size); |
6611 | int r; |
6612 | // FIXME: loop while we don't have enough random bytes. |
6613 | while (true) { |
6614 | r = RAND_bytes(buf: (unsigned char *)(buf.data()), num: size); |
6615 | if (r == 1) |
6616 | break; // success |
6617 | } |
6618 | return buf; |
6619 | } |
6620 | }; |
6621 | |
6622 | } |
6623 | |
6624 | using namespace opensslQCAPlugin; |
6625 | |
6626 | class opensslProvider : public Provider |
6627 | { |
6628 | public: |
6629 | bool openssl_initted; |
6630 | |
6631 | opensslProvider() |
6632 | { |
6633 | openssl_initted = false; |
6634 | // OPENSSL_VERSION_MAJOR is only defined in openssl3 |
6635 | #ifdef OPENSSL_VERSION_MAJOR |
6636 | /* Load the legacy providers into the default (NULL) library context */ |
6637 | if (OSSL_PROVIDER_try_load(nullptr, name: "legacy" , retain_fallbacks: 1)) { |
6638 | s_legacyProviderAvailable = true; |
6639 | } |
6640 | #else |
6641 | s_legacyProviderAvailable = true; |
6642 | #endif |
6643 | } |
6644 | |
6645 | void init() override |
6646 | { |
6647 | OpenSSL_add_all_algorithms(); |
6648 | ERR_load_crypto_strings(); |
6649 | |
6650 | // seed the RNG if it's not seeded yet |
6651 | if (RAND_status() == 0) { |
6652 | std::srand(seed: time(timer: nullptr)); |
6653 | char buf[128]; |
6654 | for (char &n : buf) |
6655 | n = std::rand(); |
6656 | RAND_seed(buf, num: 128); |
6657 | } |
6658 | |
6659 | openssl_initted = true; |
6660 | } |
6661 | |
6662 | ~opensslProvider() override |
6663 | { |
6664 | // FIXME: ? for now we never deinit, in case other libs/code |
6665 | // are using openssl |
6666 | /*if(!openssl_initted) |
6667 | return; |
6668 | // todo: any other shutdown? |
6669 | EVP_cleanup(); |
6670 | //ENGINE_cleanup(); |
6671 | CRYPTO_cleanup_all_ex_data(); |
6672 | ERR_remove_state(0); |
6673 | ERR_free_strings();*/ |
6674 | } |
6675 | |
6676 | int qcaVersion() const override |
6677 | { |
6678 | return QCA_VERSION; |
6679 | } |
6680 | |
6681 | QString name() const override |
6682 | { |
6683 | return QStringLiteral("qca-ossl" ); |
6684 | } |
6685 | |
6686 | QString credit() const override |
6687 | { |
6688 | return QStringLiteral( |
6689 | "This product includes cryptographic software " |
6690 | "written by Eric Young (eay@cryptsoft.com)" ); |
6691 | } |
6692 | |
6693 | QStringList features() const override |
6694 | { |
6695 | QStringList list; |
6696 | list += QStringLiteral("random" ); |
6697 | list += all_hash_types(); |
6698 | list += all_mac_types(); |
6699 | list += all_cipher_types(); |
6700 | if (s_legacyProviderAvailable) { |
6701 | #ifdef HAVE_OPENSSL_MD2 |
6702 | list += QStringLiteral("pbkdf1(md2)" ); |
6703 | #endif |
6704 | list += QStringLiteral("pbkdf1(sha1)" ); |
6705 | } |
6706 | list += QStringLiteral("pkcs12" ); |
6707 | list += QStringLiteral("pbkdf2(sha1)" ); |
6708 | list += QStringLiteral("hkdf(sha256)" ); |
6709 | list += QStringLiteral("pkey" ); |
6710 | list += QStringLiteral("dlgroup" ); |
6711 | list += QStringLiteral("rsa" ); |
6712 | list += QStringLiteral("dsa" ); |
6713 | list += QStringLiteral("dh" ); |
6714 | list += QStringLiteral("cert" ); |
6715 | list += QStringLiteral("csr" ); |
6716 | list += QStringLiteral("crl" ); |
6717 | list += QStringLiteral("certcollection" ); |
6718 | list += QStringLiteral("tls" ); |
6719 | list += QStringLiteral("cms" ); |
6720 | list += QStringLiteral("ca" ); |
6721 | |
6722 | return list; |
6723 | } |
6724 | |
6725 | Context *createContext(const QString &type) override |
6726 | { |
6727 | // OpenSSL_add_all_digests(); |
6728 | if (type == QLatin1String("random" )) |
6729 | return new opensslRandomContext(this); |
6730 | else if (type == QLatin1String("info" )) |
6731 | return new opensslInfoContext(this); |
6732 | else if (type == QLatin1String("sha1" )) |
6733 | return new opensslHashContext(EVP_sha1(), this, type); |
6734 | #ifdef HAVE_OPENSSL_SHA0 |
6735 | else if (type == QLatin1String("sha0" )) |
6736 | return new opensslHashContext(EVP_sha(), this, type); |
6737 | #endif |
6738 | else if (type == QLatin1String("md5" )) |
6739 | return new opensslHashContext(EVP_md5(), this, type); |
6740 | #ifdef SHA224_DIGEST_LENGTH |
6741 | else if (type == QLatin1String("sha224" )) |
6742 | return new opensslHashContext(EVP_sha224(), this, type); |
6743 | #endif |
6744 | #ifdef SHA256_DIGEST_LENGTH |
6745 | else if (type == QLatin1String("sha256" )) |
6746 | return new opensslHashContext(EVP_sha256(), this, type); |
6747 | #endif |
6748 | #ifdef SHA384_DIGEST_LENGTH |
6749 | else if (type == QLatin1String("sha384" )) |
6750 | return new opensslHashContext(EVP_sha384(), this, type); |
6751 | #endif |
6752 | #ifdef SHA512_DIGEST_LENGTH |
6753 | else if (type == QLatin1String("sha512" )) |
6754 | return new opensslHashContext(EVP_sha512(), this, type); |
6755 | #endif |
6756 | else if (type == QLatin1String("pbkdf2(sha1)" )) |
6757 | return new opensslPbkdf2Context(this, type); |
6758 | else if (type == QLatin1String("hkdf(sha256)" )) |
6759 | return new opensslHkdfContext(this, type); |
6760 | else if (type == QLatin1String("hmac(md5)" )) |
6761 | return new opensslHMACContext(EVP_md5(), this, type); |
6762 | else if (type == QLatin1String("hmac(sha1)" )) |
6763 | return new opensslHMACContext(EVP_sha1(), this, type); |
6764 | #ifdef SHA224_DIGEST_LENGTH |
6765 | else if (type == QLatin1String("hmac(sha224)" )) |
6766 | return new opensslHMACContext(EVP_sha224(), this, type); |
6767 | #endif |
6768 | #ifdef SHA256_DIGEST_LENGTH |
6769 | else if (type == QLatin1String("hmac(sha256)" )) |
6770 | return new opensslHMACContext(EVP_sha256(), this, type); |
6771 | #endif |
6772 | #ifdef SHA384_DIGEST_LENGTH |
6773 | else if (type == QLatin1String("hmac(sha384)" )) |
6774 | return new opensslHMACContext(EVP_sha384(), this, type); |
6775 | #endif |
6776 | #ifdef SHA512_DIGEST_LENGTH |
6777 | else if (type == QLatin1String("hmac(sha512)" )) |
6778 | return new opensslHMACContext(EVP_sha512(), this, type); |
6779 | #endif |
6780 | else if (type == QLatin1String("aes128-ecb" )) |
6781 | return new opensslCipherContext(EVP_aes_128_ecb(), 0, this, type); |
6782 | else if (type == QLatin1String("aes128-cfb" )) |
6783 | return new opensslCipherContext(EVP_aes_128_cfb(), 0, this, type); |
6784 | else if (type == QLatin1String("aes128-cbc" )) |
6785 | return new opensslCipherContext(EVP_aes_128_cbc(), 0, this, type); |
6786 | else if (type == QLatin1String("aes128-cbc-pkcs7" )) |
6787 | return new opensslCipherContext(EVP_aes_128_cbc(), 1, this, type); |
6788 | else if (type == QLatin1String("aes128-ofb" )) |
6789 | return new opensslCipherContext(EVP_aes_128_ofb(), 0, this, type); |
6790 | #ifdef HAVE_OPENSSL_AES_CTR |
6791 | else if (type == QLatin1String("aes128-ctr" )) |
6792 | return new opensslCipherContext(EVP_aes_128_ctr(), 0, this, type); |
6793 | #endif |
6794 | #ifdef HAVE_OPENSSL_AES_GCM |
6795 | else if (type == QLatin1String("aes128-gcm" )) |
6796 | return new opensslCipherContext(EVP_aes_128_gcm(), 0, this, type); |
6797 | #endif |
6798 | #ifdef HAVE_OPENSSL_AES_CCM |
6799 | else if (type == QLatin1String("aes128-ccm" )) |
6800 | return new opensslCipherContext(EVP_aes_128_ccm(), 0, this, type); |
6801 | #endif |
6802 | else if (type == QLatin1String("aes192-ecb" )) |
6803 | return new opensslCipherContext(EVP_aes_192_ecb(), 0, this, type); |
6804 | else if (type == QLatin1String("aes192-cfb" )) |
6805 | return new opensslCipherContext(EVP_aes_192_cfb(), 0, this, type); |
6806 | else if (type == QLatin1String("aes192-cbc" )) |
6807 | return new opensslCipherContext(EVP_aes_192_cbc(), 0, this, type); |
6808 | else if (type == QLatin1String("aes192-cbc-pkcs7" )) |
6809 | return new opensslCipherContext(EVP_aes_192_cbc(), 1, this, type); |
6810 | else if (type == QLatin1String("aes192-ofb" )) |
6811 | return new opensslCipherContext(EVP_aes_192_ofb(), 0, this, type); |
6812 | #ifdef HAVE_OPENSSL_AES_CTR |
6813 | else if (type == QLatin1String("aes192-ctr" )) |
6814 | return new opensslCipherContext(EVP_aes_192_ctr(), 0, this, type); |
6815 | #endif |
6816 | #ifdef HAVE_OPENSSL_AES_GCM |
6817 | else if (type == QLatin1String("aes192-gcm" )) |
6818 | return new opensslCipherContext(EVP_aes_192_gcm(), 0, this, type); |
6819 | #endif |
6820 | #ifdef HAVE_OPENSSL_AES_CCM |
6821 | else if (type == QLatin1String("aes192-ccm" )) |
6822 | return new opensslCipherContext(EVP_aes_192_ccm(), 0, this, type); |
6823 | #endif |
6824 | else if (type == QLatin1String("aes256-ecb" )) |
6825 | return new opensslCipherContext(EVP_aes_256_ecb(), 0, this, type); |
6826 | else if (type == QLatin1String("aes256-cfb" )) |
6827 | return new opensslCipherContext(EVP_aes_256_cfb(), 0, this, type); |
6828 | else if (type == QLatin1String("aes256-cbc" )) |
6829 | return new opensslCipherContext(EVP_aes_256_cbc(), 0, this, type); |
6830 | else if (type == QLatin1String("aes256-cbc-pkcs7" )) |
6831 | return new opensslCipherContext(EVP_aes_256_cbc(), 1, this, type); |
6832 | else if (type == QLatin1String("aes256-ofb" )) |
6833 | return new opensslCipherContext(EVP_aes_256_ofb(), 0, this, type); |
6834 | #ifdef HAVE_OPENSSL_AES_CTR |
6835 | else if (type == QLatin1String("aes256-ctr" )) |
6836 | return new opensslCipherContext(EVP_aes_256_ctr(), 0, this, type); |
6837 | #endif |
6838 | #ifdef HAVE_OPENSSL_AES_GCM |
6839 | else if (type == QLatin1String("aes256-gcm" )) |
6840 | return new opensslCipherContext(EVP_aes_256_gcm(), 0, this, type); |
6841 | #endif |
6842 | #ifdef HAVE_OPENSSL_AES_CCM |
6843 | else if (type == QLatin1String("aes256-ccm" )) |
6844 | return new opensslCipherContext(EVP_aes_256_ccm(), 0, this, type); |
6845 | #endif |
6846 | else if (type == QLatin1String("pkey" )) |
6847 | return new MyPKeyContext(this); |
6848 | else if (type == QLatin1String("dlgroup" )) |
6849 | return new MyDLGroup(this); |
6850 | else if (type == QLatin1String("rsa" )) |
6851 | return new RSAKey(this); |
6852 | else if (type == QLatin1String("dsa" )) |
6853 | return new DSAKey(this); |
6854 | else if (type == QLatin1String("dh" )) |
6855 | return new DHKey(this); |
6856 | else if (type == QLatin1String("cert" )) |
6857 | return new MyCertContext(this); |
6858 | else if (type == QLatin1String("csr" )) |
6859 | return new MyCSRContext(this); |
6860 | else if (type == QLatin1String("crl" )) |
6861 | return new MyCRLContext(this); |
6862 | else if (type == QLatin1String("certcollection" )) |
6863 | return new MyCertCollectionContext(this); |
6864 | else if (type == QLatin1String("tls" )) |
6865 | return new MyTLSContext(this); |
6866 | else if (type == QLatin1String("cms" )) |
6867 | return new CMSContext(this); |
6868 | else if (type == QLatin1String("ca" )) |
6869 | return new MyCAContext(this); |
6870 | else if (type == QLatin1String("tripledes-ecb" )) |
6871 | return new opensslCipherContext(EVP_des_ede3(), 0, this, type); |
6872 | else if (type == QLatin1String("tripledes-cbc" )) |
6873 | return new opensslCipherContext(EVP_des_ede3_cbc(), 0, this, type); |
6874 | else if (type == QLatin1String("pkcs12" )) |
6875 | return new MyPKCS12Context(this); |
6876 | |
6877 | else if (s_legacyProviderAvailable) { |
6878 | if (type == QLatin1String("blowfish-ecb" )) |
6879 | return new opensslCipherContext(EVP_bf_ecb(), 0, this, type); |
6880 | else if (type == QLatin1String("blowfish-cfb" )) |
6881 | return new opensslCipherContext(EVP_bf_cfb(), 0, this, type); |
6882 | else if (type == QLatin1String("blowfish-ofb" )) |
6883 | return new opensslCipherContext(EVP_bf_ofb(), 0, this, type); |
6884 | else if (type == QLatin1String("blowfish-cbc" )) |
6885 | return new opensslCipherContext(EVP_bf_cbc(), 0, this, type); |
6886 | else if (type == QLatin1String("blowfish-cbc-pkcs7" )) |
6887 | return new opensslCipherContext(EVP_bf_cbc(), 1, this, type); |
6888 | else if (type == QLatin1String("des-ecb" )) |
6889 | return new opensslCipherContext(EVP_des_ecb(), 0, this, type); |
6890 | else if (type == QLatin1String("des-ecb-pkcs7" )) |
6891 | return new opensslCipherContext(EVP_des_ecb(), 1, this, type); |
6892 | else if (type == QLatin1String("des-cbc" )) |
6893 | return new opensslCipherContext(EVP_des_cbc(), 0, this, type); |
6894 | else if (type == QLatin1String("des-cbc-pkcs7" )) |
6895 | return new opensslCipherContext(EVP_des_cbc(), 1, this, type); |
6896 | else if (type == QLatin1String("des-cfb" )) |
6897 | return new opensslCipherContext(EVP_des_cfb(), 0, this, type); |
6898 | else if (type == QLatin1String("des-ofb" )) |
6899 | return new opensslCipherContext(EVP_des_ofb(), 0, this, type); |
6900 | #ifndef OPENSSL_NO_CAST |
6901 | else if (type == QLatin1String("cast5-ecb" )) |
6902 | return new opensslCipherContext(EVP_cast5_ecb(), 0, this, type); |
6903 | else if (type == QLatin1String("cast5-cbc" )) |
6904 | return new opensslCipherContext(EVP_cast5_cbc(), 0, this, type); |
6905 | else if (type == QLatin1String("cast5-cbc-pkcs7" )) |
6906 | return new opensslCipherContext(EVP_cast5_cbc(), 1, this, type); |
6907 | else if (type == QLatin1String("cast5-cfb" )) |
6908 | return new opensslCipherContext(EVP_cast5_cfb(), 0, this, type); |
6909 | else if (type == QLatin1String("cast5-ofb" )) |
6910 | return new opensslCipherContext(EVP_cast5_ofb(), 0, this, type); |
6911 | #endif |
6912 | else if (type == QLatin1String("hmac(ripemd160)" )) |
6913 | return new opensslHMACContext(EVP_ripemd160(), this, type); |
6914 | else if (type == QLatin1String("ripemd160" )) |
6915 | return new opensslHashContext(EVP_ripemd160(), this, type); |
6916 | #ifdef HAVE_OPENSSL_MD2 |
6917 | else if (type == QLatin1String("md2" )) |
6918 | return new opensslHashContext(EVP_md2(), this, type); |
6919 | else if (type == QLatin1String("pbkdf1(md2)" )) |
6920 | return new opensslPbkdf1Context(EVP_md2(), this, type); |
6921 | #endif |
6922 | else if (type == QLatin1String("md4" )) |
6923 | return new opensslHashContext(EVP_md4(), this, type); |
6924 | #ifdef OBJ_whirlpool |
6925 | else if (type == QLatin1String("whirlpool" )) |
6926 | return new opensslHashContext(EVP_whirlpool(), this, type); |
6927 | #endif |
6928 | else if (type == QLatin1String("pbkdf1(sha1)" )) |
6929 | return new opensslPbkdf1Context(EVP_sha1(), this, type); |
6930 | } |
6931 | |
6932 | return nullptr; |
6933 | } |
6934 | }; |
6935 | |
6936 | class opensslPlugin : public QObject, public QCAPlugin |
6937 | { |
6938 | Q_OBJECT |
6939 | Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0" ) |
6940 | Q_INTERFACES(QCAPlugin) |
6941 | public: |
6942 | Provider *createProvider() override |
6943 | { |
6944 | return new opensslProvider; |
6945 | } |
6946 | }; |
6947 | |
6948 | #include "qca-ossl.moc" |
6949 | |