summaryrefslogtreecommitdiffstats
path: root/ui/qt/rsa_keys_frame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ui/qt/rsa_keys_frame.cpp')
-rw-r--r--ui/qt/rsa_keys_frame.cpp273
1 files changed, 273 insertions, 0 deletions
diff --git a/ui/qt/rsa_keys_frame.cpp b/ui/qt/rsa_keys_frame.cpp
new file mode 100644
index 00000000..c784ab9c
--- /dev/null
+++ b/ui/qt/rsa_keys_frame.cpp
@@ -0,0 +1,273 @@
+/* rsa_keys_frame.cpp
+ *
+ * Copyright 2019 Peter Wu <peter@lekensteyn.nl>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <config.h>
+
+#include "rsa_keys_frame.h"
+#include <ui_rsa_keys_frame.h>
+
+#include "ui/qt/widgets/wireshark_file_dialog.h"
+#include <wsutil/report_message.h>
+#include <QMessageBox>
+#include <ui/all_files_wildcard.h>
+
+#include <epan/secrets.h>
+#include <QInputDialog>
+
+#ifdef HAVE_LIBGNUTLS
+RsaKeysFrame::RsaKeysFrame(QWidget *parent) :
+ QFrame(parent),
+ ui(new Ui::RsaKeysFrame),
+ rsa_keys_model_(0),
+ pkcs11_libs_model_(0)
+{
+ ui->setupUi(this);
+
+#ifdef Q_OS_MAC
+ ui->addFileButton->setAttribute(Qt::WA_MacSmallSize, true);
+ ui->addItemButton->setAttribute(Qt::WA_MacSmallSize, true);
+ ui->deleteItemButton->setAttribute(Qt::WA_MacSmallSize, true);
+ ui->addLibraryButton->setAttribute(Qt::WA_MacSmallSize, true);
+ ui->deleteLibraryButton->setAttribute(Qt::WA_MacSmallSize, true);
+#endif
+
+#ifdef HAVE_GNUTLS_PKCS11
+ pkcs11_libs_model_ = new UatModel(this, "PKCS #11 Provider Libraries");
+ ui->libsView->setModel(pkcs11_libs_model_);
+ connect(ui->libsView->selectionModel(), &QItemSelectionModel::currentChanged,
+ this, &RsaKeysFrame::libCurrentChanged);
+#else
+ ui->addLibraryButton->setEnabled(false);
+#endif
+
+ rsa_keys_model_ = new UatModel(this, "RSA Private Keys");
+ ui->keysView->setModel(rsa_keys_model_);
+ connect(ui->keysView->selectionModel(), &QItemSelectionModel::currentChanged,
+ this, &RsaKeysFrame::keyCurrentChanged);
+}
+#else /* ! HAVE_LIBGNUTLS */
+RsaKeysFrame::RsaKeysFrame(QWidget *parent) : QFrame(parent) { }
+#endif /* ! HAVE_LIBGNUTLS */
+
+#ifdef HAVE_LIBGNUTLS
+RsaKeysFrame::~RsaKeysFrame()
+{
+ delete ui;
+}
+
+gboolean RsaKeysFrame::verifyKey(const char *uri, const char *password, gboolean *need_password, QString &error)
+{
+ char *error_c = NULL;
+ gboolean key_ok = secrets_verify_key(qPrintable(uri), qPrintable(password), need_password, &error_c);
+ error = error_c ? error_c : "";
+ g_free(error_c);
+ return key_ok;
+}
+
+void RsaKeysFrame::addKey(const QString &uri, const QString &password)
+{
+ // Create a new UAT entry with the given URI and PIN/password.
+ int row = rsa_keys_model_->rowCount();
+ rsa_keys_model_->insertRows(row, 1);
+ rsa_keys_model_->setData(rsa_keys_model_->index(row, 0), uri);
+ rsa_keys_model_->setData(rsa_keys_model_->index(row, 1), password);
+ ui->keysView->setCurrentIndex(rsa_keys_model_->index(row, 0));
+}
+
+void RsaKeysFrame::keyCurrentChanged(const QModelIndex &current, const QModelIndex & /* previous */)
+{
+ ui->deleteItemButton->setEnabled(current.isValid());
+}
+
+void RsaKeysFrame::on_addItemButton_clicked()
+{
+ GSList *keys_list = secrets_get_available_keys();
+ QStringList keys;
+ if (keys_list) {
+ for (GSList *uri = keys_list; uri; uri = uri->next) {
+ keys << (char *)uri->data;
+ }
+ g_slist_free_full(keys_list, g_free);
+ }
+
+ // Remove duplicates (keys that have already been added)
+ for (int row = rsa_keys_model_->rowCount() - 1; row >= 0; --row) {
+ QString item = rsa_keys_model_->data(rsa_keys_model_->index(row, 0)).toString();
+ keys.removeAll(item);
+ }
+
+ if (keys.isEmpty()) {
+ QMessageBox::information(this, tr("Add PKCS #11 token or key"),
+ tr("No new PKCS #11 tokens or keys found, consider adding a PKCS #11 provider."),
+ QMessageBox::Ok);
+ return;
+ }
+
+ bool ok;
+ QString item = QInputDialog::getItem(this,
+ tr("Select a new PKCS #11 token or key"),
+ tr("PKCS #11 token or key"), keys, 0, false, &ok);
+ if (!ok || item.isEmpty()) {
+ return;
+ }
+
+ // Validate the token, is a PIN needed?
+ gboolean key_ok = false, needs_pin = true;
+ QString error;
+ if (!item.startsWith("pkcs11:")) {
+ // For keys other than pkcs11, try to verify the key without password.
+ // (The PIN must always be prompted for PKCS #11 tokens, otherwise it is
+ // possible that an already unlocked token will not trigger a prompt).
+ key_ok = verifyKey(qPrintable(item), NULL, &needs_pin, error);
+ }
+ QString pin;
+ while (!key_ok && needs_pin) {
+ // A PIN is possibly needed, prompt for one.
+ QString msg;
+ if (!error.isEmpty()) {
+ msg = error + "\n";
+ error.clear();
+ }
+ msg += tr("Enter PIN or password for %1 (it will be stored unencrypted)");
+ pin = QInputDialog::getText(this, tr("Enter PIN or password for key"),
+ msg.arg(item), QLineEdit::Password, "", &ok);
+ if (!ok) {
+ return;
+ }
+ key_ok = verifyKey(qPrintable(item), qPrintable(pin), NULL, error);
+ }
+ if (!key_ok) {
+ QMessageBox::warning(this,
+ tr("Add PKCS #11 token or key"),
+ tr("Key could not be added: %1").arg(item),
+ QMessageBox::Ok);
+ return;
+ }
+
+ addKey(item, pin);
+}
+
+void RsaKeysFrame::on_addFileButton_clicked()
+{
+ QString filter =
+ tr("RSA private key (*.pem *.p12 *.pfx *.key);;All Files (" ALL_FILES_WILDCARD ")");
+ QString file = WiresharkFileDialog::getOpenFileName(this,
+ tr("Select RSA private key file"), "", filter);
+ if (file.isEmpty()) {
+ return;
+ }
+
+ // Try to load the key as unencrypted key file. If any errors occur, assume
+ // an encrypted key file and prompt for a password.
+ QString password, error;
+ gboolean key_ok = secrets_verify_key(qPrintable(file), NULL, NULL, NULL);
+ while (!key_ok) {
+ QString msg;
+ if (!error.isEmpty()) {
+ msg = error + "\n";
+ error.clear();
+ }
+ msg += QString("Enter the password to open %1").arg(file);
+
+ bool ok;
+ password = QInputDialog::getText(this, tr("Select RSA private key file"), msg,
+ QLineEdit::Password, "", &ok);
+ if (!ok) {
+ return;
+ }
+ key_ok = verifyKey(qPrintable(file), qPrintable(password), NULL, error);
+ }
+
+ addKey(file, password);
+}
+
+void RsaKeysFrame::on_deleteItemButton_clicked()
+{
+ const QModelIndex &current = ui->keysView->currentIndex();
+ if (rsa_keys_model_ && current.isValid()) {
+ rsa_keys_model_->removeRows(current.row(), 1);
+ }
+}
+
+void RsaKeysFrame::acceptChanges()
+{
+ // Save keys list mutations. The PKCS #11 provider list was already saved.
+ QString error;
+ if (rsa_keys_model_->applyChanges(error) && !error.isEmpty()) {
+ report_failure("%s", qPrintable(error));
+ }
+}
+
+void RsaKeysFrame::rejectChanges()
+{
+ // Revert keys list mutations. The PKCS #11 provider list was already saved.
+ QString error;
+ if (rsa_keys_model_->revertChanges(error) && !error.isEmpty()) {
+ report_failure("%s", qPrintable(error));
+ }
+}
+
+void RsaKeysFrame::libCurrentChanged(const QModelIndex &current, const QModelIndex & /* previous */)
+{
+ ui->deleteLibraryButton->setEnabled(current.isValid());
+}
+
+void RsaKeysFrame::on_addLibraryButton_clicked()
+{
+ if (!pkcs11_libs_model_) return;
+
+#ifdef Q_OS_WIN
+ QString filter(tr("Libraries (*.dll)"));
+#else
+ QString filter(tr("Libraries (*.so)"));
+#endif
+ QString file = WiresharkFileDialog::getOpenFileName(this, tr("Select PKCS #11 Provider Library"), "", filter);
+ if (file.isEmpty()) {
+ return;
+ }
+
+ int row = pkcs11_libs_model_->rowCount();
+ pkcs11_libs_model_->insertRows(row, 1);
+ pkcs11_libs_model_->setData(pkcs11_libs_model_->index(row, 0), file);
+ ui->libsView->setCurrentIndex(pkcs11_libs_model_->index(row, 0));
+
+ // As the libraries affect the availability of PKCS #11 tokens, we will
+ // immediately apply changes without waiting for the OK button to be
+ // activated.
+ QString error;
+ if (pkcs11_libs_model_->applyChanges(error) && error.isEmpty()) {
+ report_failure("%s", qPrintable(error));
+ }
+}
+
+void RsaKeysFrame::on_deleteLibraryButton_clicked()
+{
+ if (!pkcs11_libs_model_) return;
+
+ const QModelIndex &current = ui->libsView->currentIndex();
+ if (!current.isValid()) {
+ return;
+ }
+
+ QString file = pkcs11_libs_model_->data(current, 0).toString();
+ pkcs11_libs_model_->removeRows(current.row(), 1);
+ // Due to technical limitations of GnuTLS, libraries cannot be unloaded or
+ // disabled once loaded. Inform the user of this caveat.
+ QMessageBox::information(this, tr("Changes will apply after a restart"),
+ tr("PKCS #11 provider %1 will be removed after the next restart.").arg(file),
+ QMessageBox::Ok);
+ // Make sure the UAT is actually saved to file.
+ QString error;
+ if (pkcs11_libs_model_->applyChanges(error) && error.isEmpty()) {
+ report_failure("%s", qPrintable(error));
+ }
+}
+#endif /* HAVE_LIBGNUTLS */