Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/topics/SSHAgent.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,10 @@ If you chose to not autoload the key on database unlock, you can manually make t

.SSH Agent Load Key from Context Menu
image::sshagent_context_menu.png[]

==== Associate certificate to SSH key
If you have an externally generated OpenSSH certificate file associated with your SSH key, you can configure it in the "Certificate" tab.

When the key is loaded, if "Use certificate" is checked, both the key and certificate are added to the agent.

// end::content[]
48 changes: 48 additions & 0 deletions share/translations/keepassxc_en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3095,6 +3095,10 @@ Would you like to correct it?</source>
<source>Failed to decrypt SSH key, ensure password is correct.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select certificate</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditEntryWidgetAdvanced</name>
Expand Down Expand Up @@ -3528,6 +3532,14 @@ Would you like to correct it?</source>
<source>Clear agent</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use certificate</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Certificate</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditGroupWidget</name>
Expand Down Expand Up @@ -5347,6 +5359,22 @@ Line %2, column %3</source>
<source>Failed to open private key</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Certificate is an attachment but no attachments provided.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Certificate is empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>File too large to be a certificate</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to open certificate</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KeePass1Reader</name>
Expand Down Expand Up @@ -6844,6 +6872,18 @@ Expect some bugs and minor issues, this version is meant for testing purposes.</
<source>Failed to read public key: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Invalid or unsupported certificate file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t write certificate as it is empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unexpected EOF when writing certificate</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OpenSSHKeyGenDialog</name>
Expand Down Expand Up @@ -10043,6 +10083,14 @@ This option is deprecated, use --set-key-file instead.</source>
<source>All SSH identities removed from agent.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Agent refused this identity certificate. Possible reasons include:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Invalid or empty certificate.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SearchHelpWidget</name>
Expand Down
70 changes: 70 additions & 0 deletions src/gui/entry/EditEntryWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "core/PasswordGenerator.h"
#include "core/TimeDelta.h"
#ifdef WITH_XC_SSHAGENT
#include <QSignalBlocker>
#include "sshagent/OpenSSHKey.h"
#include "sshagent/OpenSSHKeyGenDialog.h"
#include "sshagent/SSHAgent.h"
Expand Down Expand Up @@ -538,6 +539,12 @@ void EditEntryWidget::setupEntryUpdate()
connect(m_sshAgentUi->requireUserConfirmationCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
connect(m_sshAgentUi->lifetimeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
connect(m_sshAgentUi->lifetimeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setModified()));
connect(m_sshAgentUi->attachmentCertificateRadioButton, SIGNAL(toggled(bool)), this, SLOT(setModified()));
connect(m_sshAgentUi->externalCertificateFileRadioButton, SIGNAL(toggled(bool)), this, SLOT(setModified()));
connect(m_sshAgentUi->attachmentCertificateComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setModified()));
connect(m_sshAgentUi->attachmentCertificateComboBox, SIGNAL(editTextChanged(QString)), this, SLOT(setModified()));
connect(m_sshAgentUi->externalCertificateFileEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
connect(m_sshAgentUi->addCertificateToAgentCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
}
#endif

Expand Down Expand Up @@ -615,6 +622,15 @@ void EditEntryWidget::setupSSHAgent()
connect(m_sshAgentUi->decryptButton, &QPushButton::clicked, this, &EditEntryWidget::decryptPrivateKey);
connect(m_sshAgentUi->copyToClipboardButton, &QPushButton::clicked, this, &EditEntryWidget::copyPublicKey);
connect(m_sshAgentUi->generateButton, &QPushButton::clicked, this, &EditEntryWidget::generatePrivateKey);
connect(m_sshAgentUi->attachmentCertificateRadioButton, &QRadioButton::clicked,
this, &EditEntryWidget::updateSSHAgentKeyInfo);
connect(m_sshAgentUi->attachmentCertificateComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &EditEntryWidget::updateSSHAgentAttachmentCertificate);
connect(m_sshAgentUi->externalCertificateFileRadioButton, &QRadioButton::clicked,
this, &EditEntryWidget::updateSSHAgentKeyInfo);
connect(m_sshAgentUi->externalCertificateFileEdit, &QLineEdit::textChanged,
this, &EditEntryWidget::updateSSHAgentKeyInfo);
connect(m_sshAgentUi->browseCertificateButton, &QPushButton::clicked, this, &EditEntryWidget::browseCertificate);

connect(m_attachments.data(), &EntryAttachments::modified,
this, &EditEntryWidget::updateSSHAgentAttachments);
Expand All @@ -630,10 +646,14 @@ void EditEntryWidget::setSSHAgentSettings()
m_sshAgentUi->requireUserConfirmationCheckBox->setChecked(m_sshAgentSettings.useConfirmConstraintWhenAdding());
m_sshAgentUi->lifetimeCheckBox->setChecked(m_sshAgentSettings.useLifetimeConstraintWhenAdding());
m_sshAgentUi->lifetimeSpinBox->setValue(m_sshAgentSettings.lifetimeConstraintDuration());
QSignalBlocker sshAgent_attachmentComboBox_Blocker(m_sshAgentUi->attachmentComboBox);
m_sshAgentUi->attachmentComboBox->clear();
m_sshAgentUi->addToAgentButton->setEnabled(false);
m_sshAgentUi->removeFromAgentButton->setEnabled(false);
m_sshAgentUi->copyToClipboardButton->setEnabled(false);
m_sshAgentUi->addCertificateToAgentCheckBox->setChecked(m_sshAgentSettings.useCertificate());
QSignalBlocker sshAgent_attachmentCertificateComboBox_Blocker(m_sshAgentUi->attachmentCertificateComboBox);
m_sshAgentUi->attachmentCertificateComboBox->clear(); // AlexpFr: why? attachmentCertificateComboBox init in updateSSHAgentAttachments(
Comment thread
AlexpFr marked this conversation as resolved.
Outdated
}

void EditEntryWidget::updateSSHAgent()
Expand Down Expand Up @@ -666,18 +686,25 @@ void EditEntryWidget::updateSSHAgentAttachments()
setSSHAgentSettings();
}

QSignalBlocker sshAgent_attachmentComboBox_Blocker(m_sshAgentUi->attachmentComboBox);
m_sshAgentUi->attachmentComboBox->clear();
m_sshAgentUi->attachmentComboBox->addItem("");

QSignalBlocker sshAgent_attachmentCertificateComboBox_Blocker(m_sshAgentUi->attachmentCertificateComboBox);
m_sshAgentUi->attachmentCertificateComboBox->clear();
m_sshAgentUi->attachmentCertificateComboBox->addItem("");

for (const QString& fileName : m_attachments->keys()) {
if (fileName == "KeeAgent.settings") {
continue;
}

m_sshAgentUi->attachmentComboBox->addItem(fileName);
m_sshAgentUi->attachmentCertificateComboBox->addItem(fileName);
}

m_sshAgentUi->attachmentComboBox->setCurrentText(m_sshAgentSettings.attachmentName());
QSignalBlocker sshAgent_externalFileEdit_Blocker(m_sshAgentUi->externalFileEdit);
m_sshAgentUi->externalFileEdit->setText(m_sshAgentSettings.fileName());

if (m_sshAgentSettings.selectedType() == "attachment") {
Expand All @@ -686,6 +713,16 @@ void EditEntryWidget::updateSSHAgentAttachments()
m_sshAgentUi->externalFileRadioButton->setChecked(true);
}

m_sshAgentUi->attachmentCertificateComboBox->setCurrentText(m_sshAgentSettings.attachmentNameCertificate());
QSignalBlocker sshAgent_externalCertificateFileEdit_Blocker(m_sshAgentUi->externalCertificateFileEdit);
m_sshAgentUi->externalCertificateFileEdit->setText(m_sshAgentSettings.fileNameCertificate());

if (m_sshAgentSettings.selectedCertificateType() == "attachment") {
m_sshAgentUi->attachmentCertificateRadioButton->setChecked(true);
} else {
m_sshAgentUi->externalCertificateFileRadioButton->setChecked(true);
}

updateSSHAgentKeyInfo();
}

Expand Down Expand Up @@ -752,6 +789,14 @@ void EditEntryWidget::toKeeAgentSettings(KeeAgentSettings& settings) const

// we don't use this either but we don't want it to dirty flag the config
settings.setSaveAttachmentToTempFile(m_sshAgentSettings.saveAttachmentToTempFile());

settings.setUseCertificate(m_sshAgentUi->addCertificateToAgentCheckBox->isChecked());
settings.setSelectedCertificateType(m_sshAgentUi->attachmentCertificateRadioButton->isChecked() ? "attachment" : "file");
settings.setAttachmentCertificateName(m_sshAgentUi->attachmentCertificateComboBox->currentText());
settings.setFileNameCertificate(m_sshAgentUi->externalCertificateFileEdit->text());

// we don't use this either but we don't want it to dirty flag the config
settings.setSaveAttachmentCertificateToTempFile(m_sshAgentSettings.saveAttachmentCertificateToTempFile());
}

void EditEntryWidget::updateTotp()
Expand Down Expand Up @@ -814,6 +859,23 @@ void EditEntryWidget::addKeyToAgent()
}
}

void EditEntryWidget::updateSSHAgentAttachmentCertificate()
{
m_sshAgentUi->attachmentCertificateRadioButton->setChecked(true);
updateSSHAgentKeyInfo();
}

void EditEntryWidget::browseCertificate()
{
auto fileName = fileDialog()->getOpenFileName(this, tr("Select certificate"), FileDialog::getLastDir("sshagent"));
if (!fileName.isEmpty()) {
FileDialog::saveLastDir("sshagent", fileName);
m_sshAgentUi->externalCertificateFileEdit->setText(fileName);
m_sshAgentUi->externalCertificateFileRadioButton->setChecked(true);
updateSSHAgentKeyInfo();
}
}

void EditEntryWidget::removeKeyFromAgent()
{
OpenSSHKey key;
Expand Down Expand Up @@ -960,6 +1022,9 @@ void EditEntryWidget::loadEntry(Entry* entry,

void EditEntryWidget::setForms(Entry* entry, bool restore)
{
#ifdef WITH_XC_SSHAGENT
QSignalBlocker attachmentsBlocker(m_attachments.data());
#endif
m_attachments->copyDataFrom(entry->attachments());
m_customData->copyDataFrom(entry->customData());

Expand Down Expand Up @@ -1267,6 +1332,7 @@ bool EditEntryWidget::commitEntry()
void EditEntryWidget::acceptEntry()
{
if (commitEntry()) {
m_sshAgentUi->privateKeyTabWidget->setCurrentIndex(0);
clear();
emit editFinished(true);
}
Expand Down Expand Up @@ -1386,6 +1452,7 @@ void EditEntryWidget::cancel()
}
}

m_sshAgentUi->privateKeyTabWidget->setCurrentIndex(0);
clear();
emit editFinished(accepted);
}
Expand All @@ -1405,6 +1472,9 @@ void EditEntryWidget::clear()
m_mainUi->notesEdit->clear();

m_entryAttributes->clear();
#ifdef WITH_XC_SSHAGENT
QSignalBlocker attachmentsBlocker(m_attachments.data());
#endif
m_attachments->clear();
m_customData->clear();
m_autoTypeAssoc->clear();
Expand Down
4 changes: 4 additions & 0 deletions src/gui/entry/EditEntryWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ private slots:
void decryptPrivateKey();
void copyPublicKey();
void generatePrivateKey();
void updateSSHAgentAttachmentCertificate();
void browseCertificate();
#endif
#ifdef WITH_XC_BROWSER
void updateBrowserModified();
Expand Down Expand Up @@ -186,6 +188,8 @@ private slots:
#ifdef WITH_XC_SSHAGENT
KeeAgentSettings m_sshAgentSettings;
QString m_pendingPrivateKey;
QPointer<Entry> m_entryCertificate;
const QScopedPointer<EntryAttachments> m_attachmentsCertificate;
Comment thread
AlexpFr marked this conversation as resolved.
Outdated
#endif
const QScopedPointer<Ui::EditEntryWidgetMain> m_mainUi;
const QScopedPointer<Ui::EditEntryWidgetAdvanced> m_advancedUi;
Expand Down
Loading
Loading