/* vi: set sw=4 ts=4: * * Copyright (C) 2001 - 2014 Christian Hohnstaedt. * * All rights reserved. */ #include "func.h" #include "exception.h" #include "lib/asn1time.h" #include "widgets/validity.h" #include #include #include #include #include #if defined(Q_OS_MAC) #if QT_VERSION < 0x050000 #include #else #include #endif #endif #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_OS_WIN32) #include #endif QPixmap *loadImg(const char *name ) { return new QPixmap(QString(":") + name); } QStringList getLibExtensions() { QStringList l; #if defined(_WIN32) || defined(USE_CYGWIN) l << QString("*.dll") << QString("*.DLL"); #elif defined(Q_OS_MAC) l << QString("*.dylib") << QString("*.so"); #else l << QString("*.so"); #endif return l; } /* returns e.g. /usr/local/share/xca for unix systems * or HKEY_LOCAL_MACHINE->Software->xca for WIN32 * (e.g. c:\Program Files\xca ) */ QString getPrefix() { #if defined(Q_OS_WIN32) static char inst_dir[100] = ""; char *p; ULONG dwLength = 100; LONG lRc; HKEY hKey; if (inst_dir[0] != '\0') { /* if we already once discovered the directory just return it */ return QString(inst_dir); } // fallback: directory of xca.exe GetModuleFileName(0, inst_dir, dwLength - 1); p = strrchr(inst_dir, '\\'); if (p) { *p = '\0'; return QString(inst_dir); } p = inst_dir; *p = '\0'; lRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\xca", 0, KEY_READ, &hKey); if (lRc != ERROR_SUCCESS) { XCA_WARN("Registry Key: 'HKEY_LOCAL_MACHINE->Software->xca' not found"); return QString(inst_dir); } lRc = RegQueryValueEx(hKey, "Install_Dir", NULL, NULL, (unsigned char *)inst_dir, &dwLength); if (lRc != ERROR_SUCCESS){ XCA_WARN("Registry Key: 'HKEY_LOCAL_MACHINE->Software->xca->Install_Dir' not found"); } lRc = RegCloseKey(hKey); return QString(inst_dir); #elif defined(Q_OS_MAC) // since this is platform-specific anyway, // this is a more robust way to get the bundle directory QDir bundleDir(qApp->applicationDirPath()); bundleDir.cdUp(); return bundleDir.canonicalPath() + "/Resources"; #else #ifndef XCA_PREFIX #define XCA_PREFIX PREFIX "/share/xca" #endif return QString(XCA_PREFIX); #endif } QString getHomeDir() { QString hd; #if defined(Q_OS_WIN32) LPITEMIDLIST pidl = NULL; TCHAR buf[255] = ""; if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl))) { SHGetPathFromIDList(pidl, buf); } hd = buf; #else hd = QDir::homePath(); #endif return hd; } QString getLibDir() { QString hd; #if defined(Q_OS_WIN32) LPITEMIDLIST pidl = NULL; TCHAR buf[255] = ""; if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_SYSTEM, &pidl))) { SHGetPathFromIDList(pidl, buf); } hd = buf; #else hd = QString("/usr/lib"); #endif return hd; } QString getDocDir() { #if defined(WIN32) || defined (Q_OS_MAC) return getPrefix(); #else return QString(DOCDIR); #endif } // The intent of this function is to return the proper location for // user-controlled settings on the current platform // i.e. PROFILE\Application Data\xca on windows, HOME/.xca on UNIX, // ~/Library/Preferences/xca on Mac OS X QString getUserSettingsDir() { QString rv; #if defined(Q_OS_WIN32) LPITEMIDLIST pidl = NULL; TCHAR buf[255] = ""; if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidl))) { SHGetPathFromIDList(pidl, buf); } rv = buf; rv += QDir::separator(); rv += "xca"; #elif defined(Q_OS_MAC) #if QT_VERSION < 0x050000 rv = QDesktopServices::storageLocation(QDesktopServices::DataLocation); rv.insert(rv.count() - QCoreApplication::applicationName().count(), QCoreApplication::organizationName()); #else rv = QStandardPaths::writableLocation( QStandardPaths::GenericDataLocation) + "/data/" + QCoreApplication::organizationName() + "/" + QCoreApplication::applicationName(); #endif #else rv = QDir::homePath(); rv += QDir::separator(); rv += ".xca"; #endif return rv; } // 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; QRegExp rx(".* \\( ?\\*(.[a-z]{1,3}) ?\\)"); rx.indexIn(selectedFilter); ext = rx.cap(1); if (!ext.isEmpty() && !rv.endsWith(ext)) { rv += ext; } return rv; } QByteArray filename2bytearray(const QString &fname) { #if defined(Q_OS_WIN32) return fname.toLocal8Bit(); #else return fname.toUtf8(); #endif } QString filename2QString(const char *fname) { #if defined(Q_OS_WIN32) return QString::fromLocal8Bit(fname); #else return QString::fromUtf8(fname); #endif } QString compressFilename(QString filename, int maxlen) { if (filename.length() < maxlen) return filename; QString fn = filename.replace("\\", "/"); int len, lastslash = fn.lastIndexOf('/'); QString base = filename.mid(lastslash); len = base.length(); len = maxlen - len -3; if (len < 0) return QString("...") + base.right(maxlen -3); fn = fn.left(len); lastslash = fn.lastIndexOf('/'); return filename.left(lastslash+1) + "..." + base; } QString asn1ToQString(const ASN1_STRING *str, bool quote) { QString qs; unsigned short *bmp; int i; if (!str) return qs; switch (str->type) { case V_ASN1_BMPSTRING: bmp = (unsigned short*)str->data; for (i = 0; i < str->length/2; i++) { unsigned short s = xntohs(bmp[i]); qs += QString::fromUtf16(&s, 1); } break; case V_ASN1_UTF8STRING: qs = QString::fromUtf8((const char*)str->data, str->length); break; case V_ASN1_T61STRING: qs = QString::fromLocal8Bit((const char*)str->data, str->length); break; default: qs = QString::fromLatin1((const char*)str->data, str->length); } #if 0 printf("Convert %s (%d %d) string to '%s' len %d:", ASN1_tag2str(str->type), str->type, V_ASN1_UTF8STRING, CCHAR(qs), str->length); for (int i=0; i< str->length; i++) printf(" %02x", str->data[i]); printf("\n"); #endif if (quote) qs.replace('\n', "\\n\\"); return qs; } /* 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(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.count()); ba = ba.mid(p1-p); openssl_error(); return ret; } void _openssl_error(const QString txt, const char *file, int line) { QString error; while (int i = ERR_get_error() ) { error += QString(ERR_error_string(i, NULL)) + "\n"; fputs(CCHAR(QString("OpenSSL error (%1:%2) : %3\n"). arg(file).arg(line).arg(ERR_error_string(i, NULL))), 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()) fprintf(stderr, "%s\n", CCHAR(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 fprintf(stderr, CCHAR(QString("IGNORED (%1:%2) : %3\n"). arg(file).arg(line).arg(errtxt))); #endif } return !errtxt.isEmpty(); } void inc_progress_bar(int, int, void *p) { QProgressBar *bar = (QProgressBar *)p; int value = bar->value(); if (value == bar->maximum()) { bar->reset(); } else { bar->setValue(value +1); } } bool translate_dn = false; QMap dn_translations; void dn_translations_setup() { dn_translations[NID_countryName] = QObject::tr("Country code"); dn_translations[NID_stateOrProvinceName] = QObject::tr("State or Province"); dn_translations[NID_localityName] = QObject::tr("Locality"); dn_translations[NID_organizationName] = QObject::tr("Organisation"); dn_translations[NID_organizationalUnitName] = QObject::tr("Organisational unit"); dn_translations[NID_commonName] = QObject::tr("Common name"); dn_translations[NID_pkcs9_emailAddress] = QObject::tr("E-Mail address"); dn_translations[NID_serialNumber] = QObject::tr("Serial number"); dn_translations[NID_givenName] = QObject::tr("Given name"); dn_translations[NID_surname] = QObject::tr("Surname"); dn_translations[NID_title] = QObject::tr("Title"); dn_translations[NID_initials] = QObject::tr("Initials"); dn_translations[NID_description] = QObject::tr("Description"); dn_translations[NID_role] = QObject::tr("Role"); dn_translations[NID_pseudonym] = QObject::tr("Pseudonym"); dn_translations[NID_generationQualifier] = QObject::tr("Generation Qualifier"); dn_translations[NID_x500UniqueIdentifier] = QObject::tr("x500 Unique Identifier"); dn_translations[NID_name] = QObject::tr("Name"); dn_translations[NID_dnQualifier] = QObject::tr("DN Qualifier"); dn_translations[NID_pkcs9_unstructuredName] = QObject::tr("Unstructured name"); dn_translations[NID_pkcs9_challengePassword] = QObject::tr("Challenge password"); dn_translations[NID_basic_constraints] = QObject::tr("Basic Constraints"); dn_translations[NID_subject_alt_name] = QObject::tr("Subject alternative name"); dn_translations[NID_issuer_alt_name] = QObject::tr("issuer alternative name"); dn_translations[NID_subject_key_identifier] = QObject::tr("Subject key identifier"); dn_translations[NID_authority_key_identifier] = QObject::tr("Authority key identifier"); dn_translations[NID_key_usage] = QObject::tr("Key usage"); dn_translations[NID_ext_key_usage] = QObject::tr("Extended key usage"); dn_translations[NID_crl_distribution_points] = QObject::tr("CRL distribution points"); dn_translations[NID_info_access] = QObject::tr("Authority information access"); dn_translations[NID_netscape_cert_type] = QObject::tr("Certificate type"); dn_translations[NID_netscape_base_url] = QObject::tr("Base URL"); dn_translations[NID_netscape_revocation_url] = QObject::tr("Revocation URL"); dn_translations[NID_netscape_ca_revocation_url] = QObject::tr("CA Revocation URL"); dn_translations[NID_netscape_renewal_url] = QObject::tr("Certificate renewal URL"); dn_translations[NID_netscape_ca_policy_url] = QObject::tr("CA policy URL"); dn_translations[NID_netscape_ssl_server_name] = QObject::tr("SSL server name"); dn_translations[NID_netscape_comment] = QObject::tr("Comment"); }