| 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(n: 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(date: qdate); |
| 3371 | qdt.setTime(time: 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 | |