diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bdf69c8049b9f7993504342f8140dcc1aa6adc60..0c69239c7cb05f1d7ea54301e31a0d47b0e54592 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -75,6 +75,8 @@ set( qtsflphone_LIB_SRCS audiosettingsmodel.cpp ringtonemodel.cpp lastusednumbermodel.cpp + securityvalidationmodel.cpp + certificate.cpp #Communication dbus/configurationmanager.cpp @@ -126,6 +128,8 @@ set( qtsflphone_LIB_HDRS audiosettingsmodel.h ringtonemodel.h lastusednumbermodel.h + securityvalidationmodel.h + certificate.h ) set( qtsflphone_extra_LIB_HDRS diff --git a/src/account.cpp b/src/account.cpp index 14ad4f36cdcbf82f5355317abaed064e83ff85f4..4ec4916c98ef1ed3dad8905240d2a4b86feb202a 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -33,6 +33,7 @@ #include "dbus/callmanager.h" #include "dbus/videomanager.h" #include "visitors/accountlistcolorvisitor.h" +#include "certificate.h" #include "accountlistmodel.h" #include "credentialmodel.h" #include "audiocodecmodel.h" @@ -41,6 +42,7 @@ #include "phonenumber.h" #include "phonedirectorymodel.h" #include "presencestatusmodel.h" +#include "securityvalidationmodel.h" #define TO_BOOL ?"true":"false" #define IS_TRUE == "true" @@ -58,7 +60,7 @@ const account_function Account::stateMachineActionsOnState[6][7] = { ///Constructors Account::Account():QObject(AccountListModel::instance()),m_pCredentials(nullptr),m_pAudioCodecs(nullptr),m_CurrentState(AccountEditState::READY), m_pVideoCodecs(nullptr),m_LastErrorCode(-1),m_VoiceMailCount(0),m_pRingToneModel(nullptr),m_pAccountNumber(nullptr), -m_pKeyExchangeModel(nullptr) +m_pKeyExchangeModel(nullptr),m_pSecurityValidationModel(nullptr),m_pCaCert(nullptr),m_pTlsCert(nullptr),m_pPrivateKey(nullptr) { } @@ -312,6 +314,14 @@ KeyExchangeModel* Account::keyExchangeModel() const return m_pKeyExchangeModel; } +SecurityValidationModel* Account::securityValidationModel() const +{ + if (!m_pSecurityValidationModel) { + const_cast<Account*>(this)->m_pSecurityValidationModel = new SecurityValidationModel(const_cast<Account*>(this)); + } + return m_pSecurityValidationModel; +} + void Account::setAlias(const QString& detail) { bool accChanged = detail != alias(); @@ -371,7 +381,7 @@ QString Account::password() const /// bool Account::isDisplaySasOnce() const -{ +{ return accountDetail(Account::MapField::ZRTP::DISPLAY_SAS_ONCE) IS_TRUE; } @@ -454,21 +464,30 @@ int Account::tlsListenerPort() const } ///Return the account TLS certificate authority list file -QString Account::tlsCaListFile() const +Certificate* Account::tlsCaListCertificate() const { - return accountDetail(Account::MapField::TLS::CA_LIST_FILE); + if (!m_pCaCert) + const_cast<Account*>(this)->m_pCaCert = new Certificate(Certificate::Type::AUTHORITY,this); + const_cast<Account*>(this)->m_pCaCert->setPath(accountDetail(Account::MapField::TLS::CA_LIST_FILE)); + return m_pCaCert; } ///Return the account TLS certificate -QString Account::tlsCertificateFile() const +Certificate* Account::tlsCertificate() const { - return accountDetail(Account::MapField::TLS::CERTIFICATE_FILE); + if (!m_pTlsCert) + const_cast<Account*>(this)->m_pTlsCert = new Certificate(Certificate::Type::USER,this); + const_cast<Account*>(this)->m_pTlsCert->setPath(accountDetail(Account::MapField::TLS::CERTIFICATE_FILE)); + return m_pTlsCert; } ///Return the account private key -QString Account::tlsPrivateKeyFile() const +Certificate* Account::tlsPrivateKeyCertificate() const { - return accountDetail(Account::MapField::TLS::PRIVATE_KEY_FILE); + if (!m_pPrivateKey) + const_cast<Account*>(this)->m_pPrivateKey = new Certificate(Certificate::Type::PRIVATE_KEY,this); + const_cast<Account*>(this)->m_pPrivateKey->setPath(accountDetail(Account::MapField::TLS::PRIVATE_KEY_FILE)); + return m_pPrivateKey; } ///Return the account cipher @@ -643,12 +662,12 @@ QVariant Account::roleData(int role) const // return accountPassword(); case Account::Role::TlsPassword: return tlsPassword(); - case Account::Role::TlsCaListFile: - return tlsCaListFile(); - case Account::Role::TlsCertificateFile: - return tlsCertificateFile(); - case Account::Role::TlsPrivateKeyFile: - return tlsPrivateKeyFile(); + case Account::Role::TlsCaListCertificate: + return tlsCaListCertificate()->path().toLocalFile(); + case Account::Role::TlsCertificate: + return tlsCertificate()->path().toLocalFile(); + case Account::Role::TlsPrivateKeyCertificate: + return tlsPrivateKeyCertificate()->path().toLocalFile(); case Account::Role::TlsCiphers: return tlsCiphers(); case Account::Role::TlsServerName: @@ -835,21 +854,21 @@ void Account::setTlsPassword(const QString& detail) } ///Set the certificate authority list file -void Account::setTlsCaListFile(const QString& detail) +void Account::setTlsCaListCertificate(Certificate* cert) { - setAccountDetail(Account::MapField::TLS::CA_LIST_FILE, detail); + setAccountDetail(Account::MapField::TLS::CA_LIST_FILE, cert?cert->path().toLocalFile():QString()); } ///Set the certificate -void Account::setTlsCertificateFile(const QString& detail) +void Account::setTlsCertificate(Certificate* cert) { - setAccountDetail(Account::MapField::TLS::CERTIFICATE_FILE, detail); + setAccountDetail(Account::MapField::TLS::CERTIFICATE_FILE, cert?cert->path().toLocalFile():QString()); } ///Set the private key -void Account::setTlsPrivateKeyFile(const QString& detail) +void Account::setTlsPrivateKeyCertificate(Certificate* cert) { - setAccountDetail(Account::MapField::TLS::PRIVATE_KEY_FILE, detail); + setAccountDetail(Account::MapField::TLS::PRIVATE_KEY_FILE, cert?cert->path().toLocalFile():QString()); } ///Set the TLS cipher @@ -1053,92 +1072,142 @@ void Account::setRoleData(int role, const QVariant& value) switch(role) { case Account::Role::Alias: setAlias(value.toString()); + break; case Account::Role::Proto: { const int proto = value.toInt(); setProtocol((proto>=0&&proto<=1)?static_cast<Account::Protocol>(proto):Account::Protocol::SIP); + break; } case Account::Role::Hostname: setHostname(value.toString()); + break; case Account::Role::Username: setUsername(value.toString()); + break; case Account::Role::Mailbox: setMailbox(value.toString()); + break; case Account::Role::Proxy: setProxy(value.toString()); + break; // case Password: // accountPassword(); case Account::Role::TlsPassword: setTlsPassword(value.toString()); - case Account::Role::TlsCaListFile: - setTlsCaListFile(value.toString()); - case Account::Role::TlsCertificateFile: - setTlsCertificateFile(value.toString()); - case Account::Role::TlsPrivateKeyFile: - setTlsPrivateKeyFile(value.toString()); + break; + case Account::Role::TlsCaListCertificate: { + const QString path = value.toString(); + if ((tlsCaListCertificate() && tlsCaListCertificate()->path() != QUrl(path)) || !tlsCaListCertificate()) { + tlsCaListCertificate()->setPath(path); + } + break; + } + case Account::Role::TlsCertificate: { + const QString path = value.toString(); + if ((tlsCertificate() && tlsCertificate()->path() != QUrl(path)) || !tlsCertificate()) + tlsCertificate()->setPath(path); + } + break; + case Account::Role::TlsPrivateKeyCertificate: { + const QString path = value.toString(); + if ((tlsPrivateKeyCertificate() && tlsPrivateKeyCertificate()->path() != QUrl(path)) || !tlsPrivateKeyCertificate()) + tlsPrivateKeyCertificate()->setPath(path); + } + break; case Account::Role::TlsCiphers: setTlsCiphers(value.toString()); + break; case Account::Role::TlsServerName: setTlsServerName(value.toString()); + break; case Account::Role::SipStunServer: setSipStunServer(value.toString()); + break; case Account::Role::PublishedAddress: setPublishedAddress(value.toString()); + break; case Account::Role::LocalInterface: setLocalInterface(value.toString()); + break; case Account::Role::RingtonePath: setRingtonePath(value.toString()); + break; case Account::Role::TlsMethod: { const int method = value.toInt(); setTlsMethod(method<=TlsMethodModel::instance()->rowCount()?static_cast<TlsMethodModel::Type>(method):TlsMethodModel::Type::DEFAULT); + break; } case Account::Role::KeyExchange: { const int method = value.toInt(); setKeyExchange(method<=keyExchangeModel()->rowCount()?static_cast<KeyExchangeModel::Type>(method):KeyExchangeModel::Type::NONE); + break; } case Account::Role::RegistrationExpire: setRegistrationExpire(value.toInt()); + break; case Account::Role::TlsNegotiationTimeoutSec: setTlsNegotiationTimeoutSec(value.toInt()); + break; case Account::Role::TlsNegotiationTimeoutMsec: setTlsNegotiationTimeoutMsec(value.toInt()); + break; case Account::Role::LocalPort: setLocalPort(value.toInt()); + break; case Account::Role::TlsListenerPort: setTlsListenerPort(value.toInt()); + break; case Account::Role::PublishedPort: setPublishedPort(value.toInt()); + break; case Account::Role::Enabled: setEnabled(value.toBool()); + break; case Account::Role::AutoAnswer: setAutoAnswer(value.toBool()); + break; case Account::Role::TlsVerifyServer: setTlsVerifyServer(value.toBool()); + break; case Account::Role::TlsVerifyClient: setTlsVerifyClient(value.toBool()); + break; case Account::Role::TlsRequireClientCertificate: setTlsRequireClientCertificate(value.toBool()); + break; case Account::Role::TlsEnable: setTlsEnable(value.toBool()); + break; case Account::Role::DisplaySasOnce: setDisplaySasOnce(value.toBool()); + break; case Account::Role::SrtpRtpFallback: setSrtpRtpFallback(value.toBool()); + break; case Account::Role::ZrtpDisplaySas: setZrtpDisplaySas(value.toBool()); + break; case Account::Role::ZrtpNotSuppWarning: setZrtpNotSuppWarning(value.toBool()); + break; case Account::Role::ZrtpHelloHash: setZrtpHelloHash(value.toBool()); + break; case Account::Role::SipStunEnabled: setSipStunEnabled(value.toBool()); + break; case Account::Role::PublishedSameAsLocal: setPublishedSameAsLocal(value.toBool()); + break; case Account::Role::RingtoneEnabled: setRingtoneEnabled(value.toBool()); + break; case Account::Role::dTMFType: setDTMFType((DtmfType)value.toInt()); + break; case Account::Role::Id: setId(value.toString()); + break; } } diff --git a/src/account.h b/src/account.h index e9a9de3a463f0140eb4181461f432ecd02697ae3..cf896c8135566f995c937858d90c173482487073 100644 --- a/src/account.h +++ b/src/account.h @@ -37,6 +37,8 @@ class AudioCodecModel; class VideoCodecModel; class RingToneModel ; class PhoneNumber ; +class SecurityValidationModel; +class Certificate ; const QString& account_state_name(const QString& s); @@ -66,9 +68,9 @@ class LIB_EXPORT Account : public QObject { Q_PROPERTY(QString mailbox READ mailbox WRITE setMailbox ) Q_PROPERTY(QString proxy READ proxy WRITE setProxy ) Q_PROPERTY(QString tlsPassword READ tlsPassword WRITE setTlsPassword ) - Q_PROPERTY(QString tlsCaListFile READ tlsCaListFile WRITE setTlsCaListFile ) - Q_PROPERTY(QString tlsCertificateFile READ tlsCertificateFile WRITE setTlsCertificateFile ) - Q_PROPERTY(QString tlsPrivateKeyFile READ tlsPrivateKeyFile WRITE setTlsPrivateKeyFile ) +// Q_PROPERTY(QString tlsCaListFile READ tlsCaListFile WRITE setTlsCaListFile ) +// Q_PROPERTY(QString tlsCertificateFile READ tlsCertificateFile WRITE setTlsCertificateFile ) +// Q_PROPERTY(QString tlsPrivateKeyFile READ tlsPrivateKeyFile WRITE setTlsPrivateKeyFile ) Q_PROPERTY(QString tlsCiphers READ tlsCiphers WRITE setTlsCiphers ) Q_PROPERTY(QString tlsServerName READ tlsServerName WRITE setTlsServerName ) Q_PROPERTY(QString sipStunServer READ sipStunServer WRITE setSipStunServer ) @@ -159,9 +161,9 @@ class LIB_EXPORT Account : public QObject { Mailbox = 104, Proxy = 105, TlsPassword = 107, - TlsCaListFile = 108, - TlsCertificateFile = 109, - TlsPrivateKeyFile = 110, + TlsCaListCertificate = 108, + TlsCertificate = 109, + TlsPrivateKeyCertificate = 110, TlsCiphers = 111, TlsServerName = 112, SipStunServer = 113, @@ -306,6 +308,7 @@ class LIB_EXPORT Account : public QObject { Q_INVOKABLE VideoCodecModel* videoCodecModel () const; Q_INVOKABLE RingToneModel* ringToneModel () const; Q_INVOKABLE KeyExchangeModel* keyExchangeModel() const; + Q_INVOKABLE SecurityValidationModel* securityValidationModel() const; //Getters QString hostname () const; @@ -329,9 +332,9 @@ class LIB_EXPORT Account : public QObject { int publishedPort () const; QString tlsPassword () const; int tlsListenerPort () const; - QString tlsCaListFile () const; - QString tlsCertificateFile () const; - QString tlsPrivateKeyFile () const; + Certificate* tlsCaListCertificate () const; + Certificate* tlsCertificate () const; + Certificate* tlsPrivateKeyCertificate() const; QString tlsCiphers () const; QString tlsServerName () const; int tlsNegotiationTimeoutSec () const; @@ -369,9 +372,9 @@ class LIB_EXPORT Account : public QObject { void setProxy (const QString& detail ); void setPassword (const QString& detail ); void setTlsPassword (const QString& detail ); - void setTlsCaListFile (const QString& detail ); - void setTlsCertificateFile (const QString& detail ); - void setTlsPrivateKeyFile (const QString& detail ); + void setTlsCaListCertificate (Certificate* cert ); + void setTlsCertificate (Certificate* cert ); + void setTlsPrivateKeyCertificate (Certificate* cert ); void setTlsCiphers (const QString& detail ); void setTlsServerName (const QString& detail ); void setSipStunServer (const QString& detail ); @@ -457,6 +460,7 @@ class LIB_EXPORT Account : public QObject { VideoCodecModel* m_pVideoCodecs ; RingToneModel* m_pRingToneModel ; KeyExchangeModel* m_pKeyExchangeModel; + SecurityValidationModel* m_pSecurityValidationModel; AccountEditState m_CurrentState; static const account_function stateMachineActionsOnState[6][7]; @@ -465,6 +469,9 @@ class LIB_EXPORT Account : public QObject { QString m_LastErrorMessage; int m_LastErrorCode; int m_VoiceMailCount; + Certificate* m_pCaCert; + Certificate* m_pTlsCert; + Certificate* m_pPrivateKey; Q_SIGNALS: diff --git a/src/accountlistmodel.cpp b/src/accountlistmodel.cpp index e55af067b69ece56bd68b5b481d07a7931ae3944..decb231addf3fd93c01b9f105d939263f12603f3 100644 --- a/src/accountlistmodel.cpp +++ b/src/accountlistmodel.cpp @@ -100,9 +100,9 @@ void AccountListModel::setupRoleName() roles.insert(Account::Role::Mailbox ,QByteArray("mailbox" )); roles.insert(Account::Role::Proxy ,QByteArray("proxy" )); roles.insert(Account::Role::TlsPassword ,QByteArray("tlsPassword" )); - roles.insert(Account::Role::TlsCaListFile ,QByteArray("tlsCaListFile" )); - roles.insert(Account::Role::TlsCertificateFile ,QByteArray("tlsCertificateFile" )); - roles.insert(Account::Role::TlsPrivateKeyFile ,QByteArray("tlsPrivateKeyFile" )); + roles.insert(Account::Role::TlsCaListCertificate ,QByteArray("tlsCaListCertificate" )); + roles.insert(Account::Role::TlsCertificate ,QByteArray("tlsCertificate" )); + roles.insert(Account::Role::TlsPrivateKeyCertificate ,QByteArray("tlsPrivateKeyCertificate" )); roles.insert(Account::Role::TlsCiphers ,QByteArray("tlsCiphers" )); roles.insert(Account::Role::TlsServerName ,QByteArray("tlsServerName" )); roles.insert(Account::Role::SipStunServer ,QByteArray("sipStunServer" )); diff --git a/src/certificate.cpp b/src/certificate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b40f76c3fb309265a7d2e5d38aa2cb47a950daae --- /dev/null +++ b/src/certificate.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** + * Copyright (C) 2014 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#include "certificate.h" + +#include <QtCore/QFile> + + +Certificate::Certificate(Certificate::Type type, const QObject* parent) : QObject(const_cast<QObject*>(parent)),m_Type(type) +{ + +} + +bool Certificate::exist() const +{ + return QFile::exists(m_Path.toLocalFile()); +} + +QUrl Certificate::path() const +{ + return m_Path; +} + +void Certificate::setPath(const QUrl& path) +{ + m_Path = path; +} + +bool Certificate::isExpired() const +{ + return true; //TODO +} + +bool Certificate::isSelfSigned() const +{ + return true; //TODO +} + +bool Certificate::hasPrivateKey() const +{ + return false; //TODO +} + +bool Certificate::hasProtectedPrivateKey() const +{ + return false; //TODO +} + +bool Certificate::hasRightPermissions() const +{ + return false; //TODO +} + +bool Certificate::hasRightFolderPermissions() const +{ + return false; //TODO +} + +bool Certificate::isLocationSecure() const +{ + return false; //TODO +} + +Certificate::Type Certificate::type() const +{ + return m_Type; +} diff --git a/src/certificate.h b/src/certificate.h new file mode 100644 index 0000000000000000000000000000000000000000..005942648caaff7d75a50f13e7c52ce88d53beb7 --- /dev/null +++ b/src/certificate.h @@ -0,0 +1,64 @@ +/**************************************************************************** + * Copyright (C) 2014 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#ifndef CERTIFICATE_H +#define CERTIFICATE_H + +#include "typedefs.h" + +//Qt +#include <QUrl> + +class LIB_EXPORT Certificate : public QObject { + Q_OBJECT +public: + + //Structures + enum class Type { + AUTHORITY , + USER , + PRIVATE_KEY, + NONE , + }; + + Certificate(Certificate::Type type ,const QObject* parent = nullptr); + + //Getter + QUrl path() const; + Certificate::Type type() const; + + //Setter + void setPath(const QUrl& path); + + //Validation + bool exist () const; + bool isExpired () const; + bool isSelfSigned () const; + bool hasPrivateKey () const; + bool hasProtectedPrivateKey () const; + bool hasRightPermissions () const; + bool hasRightFolderPermissions() const; + bool isLocationSecure () const; + +private: + QUrl m_Path; + Certificate::Type m_Type; + //TODO +}; +Q_DECLARE_METATYPE(Certificate*) + +#endif \ No newline at end of file diff --git a/src/securityvalidationmodel.cpp b/src/securityvalidationmodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a16af6db33eee7f1a63edc2047e49fcb31cc9517 --- /dev/null +++ b/src/securityvalidationmodel.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** + * Copyright (C) 2013-2014 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#include "securityvalidationmodel.h" +#include "account.h" +#include "visitors/pixmapmanipulationvisitor.h" + +const QString SecurityValidationModel::messages[static_cast<const int>(SecurityFlaw::COUNT)] = { + QObject::tr("Your communication negotation is secured, but not the media stream, please enable ZRTP or SDES"), + QObject::tr("TLS is disabled, the negotiation wont be encrypted. Your communication will be vulnerable to " + "snooping"), + QObject::tr("Your certificate is expired, please contact your system administrator."), + QObject::tr("Your certificate is self signed. This break the chain of trust."), + QObject::tr("CA_CERTIFICATE_MISSING "), + QObject::tr("END_CERTIFICATE_MISSING "), + QObject::tr("None of your certificate provide a private key, this is required. Please select a private key" + " or use a certificate with one built-in"), + QObject::tr("CERTIFICATE_MISMATCH "), + QObject::tr("CERTIFICATE_STORAGE_PERMISSION "), + QObject::tr("CERTIFICATE_STORAGE_FOLDER "), + QObject::tr("CERTIFICATE_STORAGE_LOCATION "), + QObject::tr("OUTGOING_SERVER_MISMATCH "), + QObject::tr("VERIFY_INCOMING_DISABLED "), + QObject::tr("VERIFY_ANSWER_DISABLED "), + QObject::tr("REQUIRE_CERTIFICATE_DISABLED "), +}; + +const TypedStateMachine< SecurityValidationModel::SecurityLevel , SecurityValidationModel::SecurityFlaw > +SecurityValidationModel::maximumSecurityLevel = {{ + /* SRTP_DISABLED */ SecurityLevel::WEAK , + /* TLS_DISABLED */ SecurityLevel::WEAK , + /* CERTIFICATE_EXPIRED */ SecurityLevel::MEDIUM , + /* CERTIFICATE_SELF_SIGNED */ SecurityLevel::MEDIUM , + /* CA_CERTIFICATE_MISSING */ SecurityLevel::PARTIAL , + /* END_CERTIFICATE_MISSING */ SecurityLevel::PARTIAL , + /* PRIVATE_KEY_MISSING */ SecurityLevel::PARTIAL , + /* CERTIFICATE_MISMATCH */ SecurityLevel::NONE , + /* CERTIFICATE_STORAGE_PERMISSION */ SecurityLevel::ACCEPTABLE , + /* CERTIFICATE_STORAGE_FOLDER */ SecurityLevel::ACCEPTABLE , + /* CERTIFICATE_STORAGE_LOCATION */ SecurityLevel::ACCEPTABLE , + /* OUTGOING_SERVER_MISMATCH */ SecurityLevel::ACCEPTABLE , + /* VERIFY_INCOMING_DISABLED */ SecurityLevel::PARTIAL , + /* VERIFY_ANSWER_DISABLED */ SecurityLevel::PARTIAL , + /* REQUIRE_CERTIFICATE_DISABLED */ SecurityLevel::PARTIAL , + /* MISSING_CERTIFICATE */ SecurityLevel::NONE , + /* MISSING_AUTHORITY */ SecurityLevel::WEAK , +}}; + +const TypedStateMachine< SecurityValidationModel::Severity , SecurityValidationModel::SecurityFlaw > +SecurityValidationModel::flawSeverity = {{ + /* SRTP_DISABLED */ Severity::ISSUE , + /* TLS_DISABLED */ Severity::ISSUE , + /* CERTIFICATE_EXPIRED */ Severity::WARNING , + /* CERTIFICATE_SELF_SIGNED */ Severity::WARNING , + /* CA_CERTIFICATE_MISSING */ Severity::ISSUE , + /* END_CERTIFICATE_MISSING */ Severity::ISSUE , + /* PRIVATE_KEY_MISSING */ Severity::ERROR , + /* CERTIFICATE_MISMATCH */ Severity::ERROR , + /* CERTIFICATE_STORAGE_PERMISSION */ Severity::WARNING , + /* CERTIFICATE_STORAGE_FOLDER */ Severity::INFORMATION , + /* CERTIFICATE_STORAGE_LOCATION */ Severity::INFORMATION , + /* OUTGOING_SERVER_MISMATCH */ Severity::WARNING , + /* VERIFY_INCOMING_DISABLED */ Severity::ISSUE , + /* VERIFY_ANSWER_DISABLED */ Severity::ISSUE , + /* REQUIRE_CERTIFICATE_DISABLED */ Severity::ISSUE , + /* MISSING_CERTIFICATE */ Severity::ERROR , + /* MISSING_AUTHORITY */ Severity::ERROR , +}}; + + +SecurityValidationModel::SecurityValidationModel(Account* account) : QAbstractListModel(account), m_pAccount(account) +{ + +} + +SecurityValidationModel::~SecurityValidationModel() +{ + +} + +QVariant SecurityValidationModel::data( const QModelIndex& index, int role) const +{ + if (index.isValid()) { + if (role == Qt::DisplayRole) { + return messages[static_cast<int>( m_lCurrentFlaws[index.row()].flaw )]; + } + else if (role == Role::SeverityRole) { + return static_cast<int>(m_lCurrentFlaws[index.row()].severity); + } + else if (role == Qt::DecorationRole) { + return PixmapManipulationVisitor::instance()->serurityIssueIcon(index); + } + } + return QVariant(); +} + +int SecurityValidationModel::rowCount( const QModelIndex& parent) const +{ + Q_UNUSED(parent) + return m_lCurrentFlaws.size(); +} + +Qt::ItemFlags SecurityValidationModel::flags( const QModelIndex& index) const +{ + if (!index.isValid()) return Qt::NoItemFlags; + return Qt::ItemIsEnabled|Qt::ItemIsSelectable; +} + +bool SecurityValidationModel::setData( const QModelIndex& index, const QVariant &value, int role) +{ + Q_UNUSED(index) + Q_UNUSED(value) + Q_UNUSED(role ) + return false; +} + +void SecurityValidationModel::update() +{ + m_lCurrentFlaws.clear(); + + /********************************** + * Check general issues * + *********************************/ + + /* If TLS is not enabled, everything else is worthless */ + if (!m_pAccount->isTlsEnable()) { + m_lCurrentFlaws << Flaw(SecurityFlaw::TLS_DISABLED); + } + + /* Check if the media stream is encrypted, it is something users + * may care about if they get this far ;) */ + if (!m_pAccount->isSrtpEnabled()) { + m_lCurrentFlaws << Flaw(SecurityFlaw::SRTP_DISABLED); + } + + /* The user certificate need to have a private key, otherwise it wont + * be possible to encrypt anything */ + if ((! m_pAccount->tlsCertificate()->hasPrivateKey()) && (!m_pAccount->tlsPrivateKeyCertificate()->exist())) { + m_lCurrentFlaws << Flaw(SecurityFlaw::PRIVATE_KEY_MISSING,m_pAccount->tlsPrivateKeyCertificate()->type()); + } + + /********************************** + * Certificates issues * + *********************************/ + QList<Certificate*> certs; + certs << m_pAccount->tlsCaListCertificate() << m_pAccount->tlsCertificate() << m_pAccount->tlsPrivateKeyCertificate(); + foreach (Certificate* cert, certs) { + if (! cert->exist()) { + m_lCurrentFlaws << Flaw(SecurityFlaw::END_CERTIFICATE_MISSING,cert->type()); + } + if (! cert->isExpired()) { + m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_EXPIRED,cert->type()); + } + if (! cert->isSelfSigned()) { + m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_SELF_SIGNED,cert->type()); + } + if (! cert->hasProtectedPrivateKey()) { + m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_PERMISSION,cert->type()); + } + if (! cert->hasRightPermissions()) { + m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_PERMISSION),cert->type(); + } + if (! cert->hasRightFolderPermissions()) { + m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_FOLDER,cert->type()); + } + if (! cert->isLocationSecure()) { + m_lCurrentFlaws << Flaw(SecurityFlaw::CERTIFICATE_STORAGE_LOCATION,cert->type()); + } + } + + emit layoutChanged(); +} + + diff --git a/src/securityvalidationmodel.h b/src/securityvalidationmodel.h new file mode 100644 index 0000000000000000000000000000000000000000..2ef6b85f9a68e7c78a302e8fc82a00796323441f --- /dev/null +++ b/src/securityvalidationmodel.h @@ -0,0 +1,142 @@ +/**************************************************************************** + * Copyright (C) 2013-2014 by Savoir-Faire Linux *** + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#ifndef SECURITYVALIDATIONMODEL_H +#define SECURITYVALIDATIONMODEL_H +#include <QAbstractListModel> + +//SFLPhone +#include "certificate.h" +#include "typedefs.h" + + +//SFLPhone +class Account; + +class LIB_EXPORT SecurityValidationModel : public QAbstractListModel { + Q_OBJECT +public: + /* + * This class evaluate the overall security of an account. + * It does so by checking various potential flaws, then create + * a metric called SecurityLevel. This model should be used to: + * + * 1) List all potential flaws + * 2) Decide if an account can be considered secure + * 3) Decide if a call can be considered secure + * + * End users should not have to be security gurus to setup SFLphone. It is our + * job to do as much as we can to make security configuration as transparent as + * possible. + * + * The SecurityLevel is computed by checking all possible flaw. The level cannot be + * higher than a flaw maximum security level. If there is 2 (or more) flaw in the same + * maximum level, the maximum level will be decreased by one (recursively). + * + * A flaw severity is used by the client to display the right icon ( (i), /!\, [x] ). + */ + + ///Give the user an overview of the current security state + enum class SecurityLevel { + NONE = 0, /* Security is not functional or severely defective */ + WEAK = 1, /* There is some security, but way too many flaws */ + PARTIAL = 2, /* There is some security, but there is too many flaws */ + MEDIUM = 3, /* The security is probably good enough, but there is issues */ + ACCEPTABLE = 4, /* The security is most probably good enough, only minor issues */ + STRONG = 5, /* All the non-information items are correct */ + VERY_STRONG = 6, /* Everything, even the recommendations, are correct */ + }; + + ///The severity of a given flaw + enum class Severity { + INFORMATION , /* Tip and tricks to have better security */ + WARNING , /* It is a problem, but it wont have other side effects */ + ISSUE , /* The security is compromised */ + ERROR , /* It simply wont work (REGISTER) */ + FATAL_WARNING, /* Registration may work, but it render everything else useless */ + }; + + ///Every supported flaws + enum class SecurityFlaw { + SRTP_DISABLED , + TLS_DISABLED , + CERTIFICATE_EXPIRED , + CERTIFICATE_SELF_SIGNED , + CA_CERTIFICATE_MISSING , + END_CERTIFICATE_MISSING , + PRIVATE_KEY_MISSING , + CERTIFICATE_MISMATCH , + CERTIFICATE_STORAGE_PERMISSION , + CERTIFICATE_STORAGE_FOLDER , + CERTIFICATE_STORAGE_LOCATION , + OUTGOING_SERVER_MISMATCH , + VERIFY_INCOMING_DISABLED , + VERIFY_ANSWER_DISABLED , + REQUIRE_CERTIFICATE_DISABLED , + MISSING_CERTIFICATE , + MISSING_AUTHORITY , + COUNT + }; + + ///Role for the model + enum Role { + SeverityRole = 100 + }; + + ///Messages to show to the end user + static const QString messages[static_cast<const int>(SecurityFlaw::COUNT)]; + + ///A flaw representation + struct Flaw { + Flaw(SecurityFlaw f,Certificate::Type type = Certificate::Type::NONE) + : flaw(f),certType(type) + { + severity = flawSeverity[f]; + } + SecurityFlaw flaw; + Severity severity; + Certificate::Type certType; + }; + + //Constructor + SecurityValidationModel(Account* account); + virtual ~SecurityValidationModel(); + + + //Model functions + QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const; + int rowCount ( const QModelIndex& parent = QModelIndex() ) const; + Qt::ItemFlags flags ( const QModelIndex& index ) const; + virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) ; + + //Mutator + void update(); + +private: + //Attributes + QList<Flaw> m_lCurrentFlaws ; + SecurityLevel m_CurrentSecurityLevel; + Account* m_pAccount ; + +private: + //Static mapping + static const TypedStateMachine< SecurityLevel , SecurityFlaw > maximumSecurityLevel; + static const TypedStateMachine< Severity , SecurityFlaw > flawSeverity ; +}; +Q_DECLARE_METATYPE(SecurityValidationModel*) + +#endif \ No newline at end of file diff --git a/src/visitors/pixmapmanipulationvisitor.cpp b/src/visitors/pixmapmanipulationvisitor.cpp index da3a7978fb9005f78a2f68549232a493253c1fb1..04a7ce41a4040e288c97caa128dbd30bd963d68a 100644 --- a/src/visitors/pixmapmanipulationvisitor.cpp +++ b/src/visitors/pixmapmanipulationvisitor.cpp @@ -62,3 +62,9 @@ PixmapManipulationVisitor* PixmapManipulationVisitor::instance() { return m_spInstance; } + +QVariant PixmapManipulationVisitor::serurityIssueIcon(const QModelIndex& index) +{ + Q_UNUSED(index) + return QVariant(); +} diff --git a/src/visitors/pixmapmanipulationvisitor.h b/src/visitors/pixmapmanipulationvisitor.h index de6b9a71f96626a0a82d9fa8798c21df308756b8..83e1fa2a0b4895d249351b7426ba64a91d6cb0f6 100644 --- a/src/visitors/pixmapmanipulationvisitor.h +++ b/src/visitors/pixmapmanipulationvisitor.h @@ -21,6 +21,7 @@ //Qt #include <QtCore/QVariant> +#include <QtCore/QModelIndex> //SFLPhone class Contact ; @@ -45,6 +46,7 @@ public: virtual QVariant callPhoto(Call* c, const QSize& size, bool displayPresence = true); virtual QVariant callPhoto(const PhoneNumber* n, const QSize& size, bool displayPresence = true); virtual QVariant numberCategoryIcon(const QPixmap* p, const QSize& size, bool displayPresence = false, bool isPresent = false); + virtual QVariant serurityIssueIcon(const QModelIndex& index); //Singleton static PixmapManipulationVisitor* instance();