/* vi: set sw=4 ts=4: * * Copyright (C) 2001 - 2014 Christian Hohnstaedt. * * All rights reserved. */ #include "func_base.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "exception.h" bool is_gui_app = false; const QStringList getLibExtensions() { return QStringList { #if defined(Q_OS_WIN32) QString("*.dll"), QString("*.DLL"), #elif defined(Q_OS_MACOS) QString("*.dylib"), QString("*.so"), #else QString("*.so"), #endif }; } // Qt's open and save dialogs result in some undesirable quirks. // This function makes sure that a filename has the user-selected extension. QString getFullFilename(const QString & filename, const QString & selectedFilter) { QString rv = filename.trimmed(), ext; auto match = QRegularExpression(".* \\( ?\\*(.[a-z]{1,3}) ?\\)") .match(selectedFilter); ext = match.captured(1); if (ext.isEmpty() || rv.endsWith(ext)) return rv; return rv + ext; } QString compressFilename(const QString &filename, int maxlen) { QString fn = filename; if (fn.length() >= maxlen) { fn.replace("\\", "/"); int len, lastslash = fn.lastIndexOf('/'); QString base = filename.mid(lastslash); len = maxlen - base.length() - 3; if (len < 0) { fn = "..." + base.right(maxlen -3); } else { fn = fn.left(len); lastslash = fn.lastIndexOf('/'); fn = filename.left(lastslash + 1) + "..." + base; } } return nativeSeparator(fn); } QString asn1ToQString(const ASN1_STRING *str, bool quote) { unsigned char *out = NULL; int len; QString utf8; len = ASN1_STRING_to_UTF8(&out, str); if (len != -1) { utf8 = QString::fromUtf8((const char*)out, len); OPENSSL_free(out); } if (quote) utf8.replace('\n', "\\n\\"); return utf8; } /* returns an encoded ASN1 string from QString for a special nid*/ ASN1_STRING *QStringToAsn1(const QString s, int nid) { QByteArray ba = s.toUtf8(); const unsigned char *utf8 = (const unsigned char *)ba.constData(); unsigned long global_mask = ASN1_STRING_get_default_mask(); unsigned long mask = DIRSTRING_TYPE & global_mask; ASN1_STRING *out = NULL; ASN1_STRING_TABLE *tbl; tbl = ASN1_STRING_TABLE_get(nid); if (tbl) { mask = tbl->mask; if (!(tbl->flags & STABLE_NO_MASK)) mask &= global_mask; } ASN1_mbstring_copy(&out, utf8, -1, MBSTRING_UTF8, mask); openssl_error_msg(QString("'%1' (%2)").arg(s).arg(OBJ_nid2ln(nid))); return out; } const char *OBJ_ln2sn(const char *ln) { return OBJ_nid2sn(OBJ_ln2nid(ln)); } const char *OBJ_sn2ln(const char *sn) { return OBJ_nid2ln(OBJ_sn2nid(sn)); } const char *OBJ_obj2sn(ASN1_OBJECT *a) { OBJ_obj2nid(a); openssl_error(); return OBJ_nid2sn(OBJ_obj2nid(a)); } QString OBJ_obj2QString(const ASN1_OBJECT *a, int no_name) { char buf[512]; int len; len = OBJ_obj2txt(buf, sizeof buf, a, no_name); openssl_error(); return QString::fromLatin1(buf, len); } QByteArray i2d_bytearray(int(*i2d)(const void*, unsigned char **), const void *data) { QByteArray ba; ba.resize(i2d(data, NULL)); unsigned char *p = (unsigned char*)ba.data(); i2d(data, &p); openssl_error(); return ba; } void *d2i_bytearray(void *(*d2i)(void *, unsigned char **, long), QByteArray &ba) { unsigned char *p, *p1; void *ret; p = p1 = (unsigned char *)ba.constData(); ret = d2i(NULL, &p1, ba.size()); ba = ba.mid(p1-p); openssl_error(); return ret; } static int __ecb(const char *st, size_t len, void *u) { QByteArray *ba = (QByteArray *)u; ba->append(st, len); return 1; } void _openssl_error(const QString &txt, const char *file, int line) { QString error; QByteArray ba; ERR_print_errors_cb(__ecb, &ba); if (!ba.isEmpty()) { fputs(CCHAR(QString("OpenSSL error (%1:%2) : %3\n"). arg(file).arg(line).arg(QString::fromLatin1(ba))), stderr); } if (!error.isEmpty()) { if (!txt.isEmpty()) error = txt + "\n" + error + "\n" + QString("(%1:%2)").arg(file).arg(line); throw errorEx(error); } } #undef PRINT_IGNORED_ANYWAY bool _ign_openssl_error(const QString &txt, const char *file, int line) { // ignore openssl errors QString errtxt; #if PRINT_IGNORED_ANYWAY if (!txt.isEmpty() && ERR_peek_error()) qDebug() << txt; #else (void)txt; (void)file; (void)line; #endif while (int i = ERR_get_error() ) { errtxt = ERR_error_string(i, NULL); #if PRINT_IGNORED_ANYWAY qDebug() << QString("IGNORED (%1:%2) : %3\n") .arg(file).arg(line).arg(errtxt); #endif } return !errtxt.isEmpty(); } QString formatHash(const QByteArray &data, QString sep, int width) { return QString(data.toHex()).toUpper() .replace(QRegularExpression(QString("(.{%1})(?=.)").arg(width)), QString("\\1") + sep); } QByteArray Digest(const QByteArray &data, const EVP_MD *type) { unsigned int n; unsigned char m[EVP_MAX_MD_SIZE]; EVP_Digest(data.constData(), data.size(), m, &n, type, NULL); openssl_error(); return QByteArray((char*)m, (int)n); } QString get_ossl_verify_error(int err) { // https://docs.openssl.org/master/man3/X509_STORE_CTX_get_error/#error-codes static const QMap ossl_verify_errors = { #define V_ERR(x) { x, #x }, V_ERR(X509_V_OK) #include "openssl_v_err.c" }; return ossl_verify_errors.value(err, "Unknown error"); } QMap dn_translations; void dn_translations_setup() { QMap D; D[NID_countryName] = QObject::tr("Country code"); D[NID_stateOrProvinceName] = QObject::tr("State or Province"); D[NID_localityName] = QObject::tr("Locality"); D[NID_organizationName] = QObject::tr("Organisation"); D[NID_organizationalUnitName] = QObject::tr("Organisational unit"); D[NID_commonName] = QObject::tr("Common name"); D[NID_pkcs9_emailAddress] = QObject::tr("E-Mail address"); D[NID_serialNumber] = QObject::tr("Serial number"); D[NID_givenName] = QObject::tr("Given name"); D[NID_surname] = QObject::tr("Surname"); D[NID_title] = QObject::tr("Title"); D[NID_initials] = QObject::tr("Initials"); D[NID_description] = QObject::tr("Description"); D[NID_role] = QObject::tr("Role"); D[NID_pseudonym] = QObject::tr("Pseudonym"); D[NID_generationQualifier] = QObject::tr("Generation Qualifier"); D[NID_x500UniqueIdentifier] = QObject::tr("x500 Unique Identifier"); D[NID_name] = QObject::tr("Name"); D[NID_dnQualifier] = QObject::tr("DN Qualifier"); D[NID_pkcs9_unstructuredName] = QObject::tr("Unstructured name"); D[NID_pkcs9_challengePassword] = QObject::tr("Challenge password"); D[NID_basic_constraints] = QObject::tr("Basic Constraints"); D[NID_name_constraints] = QObject::tr("Name Constraints"); D[NID_subject_alt_name] = QObject::tr("Subject alternative name"); D[NID_issuer_alt_name] = QObject::tr("issuer alternative name"); D[NID_subject_key_identifier] = QObject::tr("Subject key identifier"); D[NID_authority_key_identifier] = QObject::tr("Authority key identifier"); D[NID_key_usage] = QObject::tr("Key usage"); D[NID_ext_key_usage] = QObject::tr("Extended key usage"); D[NID_crl_distribution_points] = QObject::tr("CRL distribution points"); D[NID_info_access] = QObject::tr("Authority information access"); D[NID_netscape_cert_type] = QObject::tr("Certificate type"); D[NID_netscape_base_url] = QObject::tr("Base URL"); D[NID_netscape_revocation_url] = QObject::tr("Revocation URL"); D[NID_netscape_ca_revocation_url] = QObject::tr("CA Revocation URL"); D[NID_netscape_renewal_url] = QObject::tr("Certificate renewal URL"); D[NID_netscape_ca_policy_url] = QObject::tr("CA policy URL"); D[NID_netscape_ssl_server_name] = QObject::tr("SSL server name"); D[NID_netscape_comment] = QObject::tr("Comment"); dn_translations = D; } QString appendXcaComment(QString current, QString msg) { if (!current.endsWith("\n") && !current.isEmpty()) current += "\n"; return current + QString("(%1)\n").arg(msg); }