Skip to content

Commit

Permalink
Add Polkit Quick Unlock Support
Browse files Browse the repository at this point in the history
Closes keepassxreboot#5991
Closes keepassxreboot#3337 - Support fingerprint readers on Linux

Polkit allows for authentication of many means, including fingerprint scanning. Furthermore, a common interface for Quick Unlocking has been implemented, and has been replaced throughout to make implementing other quick unlock strategies easier.

Refactor QuickUnlock to use UUID stored in headers. This is a new feature using the KDBX 4 standard to store a randomly generated UUID in the public headers of the database. This enables identification of KDBX file without relying on path or filename and will eventually support persistent Quick Unlock.
  • Loading branch information
HexF authored and droidmonkey committed Sep 4, 2023
1 parent 1919c23 commit a5a4c16
Show file tree
Hide file tree
Showing 27 changed files with 793 additions and 225 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Expand Up @@ -37,7 +37,7 @@ jobs:
run: |
sudo apt update
sudo apt install build-essential cmake g++
sudo apt install qtbase5-dev qtbase5-private-dev qttools5-dev qttools5-dev-tools libqt5svg5-dev libargon2-dev libminizip-dev libbotan-2-dev libqrencode-dev zlib1g-dev asciidoctor libreadline-dev libpcsclite-dev libusb-1.0-0-dev libxi-dev libxtst-dev libqt5x11extras5-dev
sudo apt install qtbase5-dev qtbase5-private-dev qttools5-dev qttools5-dev-tools libqt5svg5-dev libargon2-dev libkeyutils-dev libminizip-dev libbotan-2-dev libqrencode-dev zlib1g-dev asciidoctor libreadline-dev libpcsclite-dev libusb-1.0-0-dev libxi-dev libxtst-dev libqt5x11extras5-dev
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
Expand Down
2 changes: 1 addition & 1 deletion cmake/CLangFormat.cmake
Expand Up @@ -18,7 +18,7 @@ set(EXCLUDED_DIRS
src/thirdparty
src/zxcvbn
# objective-c directories
src/touchid
src/quickunlock/touchid
src/autotype/mac
src/gui/osutils/macutils)

Expand Down
5 changes: 5 additions & 0 deletions share/CMakeLists.txt
Expand Up @@ -58,7 +58,12 @@ if(UNIX AND NOT APPLE AND NOT HAIKU)
EXCLUDE PATTERN "actions" EXCLUDE PATTERN "categories" EXCLUDE)
endif(KEEPASSXC_DIST_FLATPAK)
configure_file(linux/${APP_ID}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/linux/${APP_ID}.desktop @ONLY)
configure_file(linux/${APP_ID}.policy.in ${CMAKE_CURRENT_BINARY_DIR}/linux/${APP_ID}.policy @ONLY)

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/linux/${APP_ID}.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
if("${CMAKE_SYSTEM}" MATCHES "Linux")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/linux/${APP_ID}.policy DESTINATION ${CMAKE_INSTALL_DATADIR}/polkit-1/actions)
endif()
install(FILES linux/${APP_ID}.appdata.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo)
endif(UNIX AND NOT APPLE AND NOT HAIKU)

Expand Down
18 changes: 18 additions & 0 deletions share/linux/org.keepassxc.KeePassXC.policy.in
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE policyconfig PUBLIC
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
<policyconfig>
<vendor>KeePassXC Developers</vendor>
<vendor_url></vendor_url>
<icon_name>@APP_ICON_NAME@</icon_name>

<action id="org.keepassxc.KeePassXC.unlockDatabase">
<description>Quick Unlock for a KeePassXC Database</description>
<message>Authentication is required to unlock a KeePassXC Database</message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>auth_self</allow_active>
</defaults>
</action>
</policyconfig>
46 changes: 37 additions & 9 deletions share/translations/keepassxc_en.ts
Expand Up @@ -1518,10 +1518,6 @@ To prevent this error from appearing, you must go to &quot;Database Settings / S
<source>Retry with empty password</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to authenticate with Touch ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to open key file: %1</source>
<translation type="unfinished"></translation>
Expand Down Expand Up @@ -1576,11 +1572,7 @@ If you do not have a key file, please leave the field empty.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to authenticate with Windows Hello: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Windows Hello setup was canceled or failed. Quick unlock has not been enabled.</source>
<source>Failed to authenticate with Quick Unlock: %1</source>
<translation type="unfinished"></translation>
</message>
</context>
Expand Down Expand Up @@ -7979,6 +7971,42 @@ Kernel: %3 %4</source>
<source>allow screenshots and app recording (Windows/macOS)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AES initialization failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AES encrypt failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to store in Linux Keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Could not locate key in keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Could not read key in keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AES decrypt failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No Polkit authentication agent was available</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Polkit authorization failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No Quick Unlock provider is available</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtIOCompressor</name>
Expand Down
29 changes: 26 additions & 3 deletions src/CMakeLists.txt
Expand Up @@ -193,6 +193,7 @@ set(keepassx_SOURCES
streams/qtiocompressor.cpp
streams/StoreDataStream.cpp
streams/SymmetricCipherStream.cpp
quickunlock/QuickUnlockInterface.cpp
totp/totp.cpp)
if(APPLE)
set(keepassx_SOURCES
Expand All @@ -208,6 +209,12 @@ if(UNIX AND NOT APPLE)
${keepassx_SOURCES}
gui/osutils/nixutils/ScreenLockListenerDBus.cpp
gui/osutils/nixutils/NixUtils.cpp)
if("${CMAKE_SYSTEM}" MATCHES "Linux")
set(keepassx_SOURCES
${keepassx_SOURCES}
quickunlock/Polkit.cpp
quickunlock/PolkitDbusTypes.cpp)
endif()
if(WITH_XC_X11)
list(APPEND keepassx_SOURCES
gui/osutils/nixutils/X11Funcs.cpp)
Expand All @@ -216,14 +223,29 @@ if(UNIX AND NOT APPLE)
gui/org.keepassxc.KeePassXC.MainWindow.xml
gui/MainWindow.h
MainWindow)

set_source_files_properties(
quickunlock/dbus/org.freedesktop.PolicyKit1.Authority.xml
PROPERTIES
INCLUDE "quickunlock/PolkitDbusTypes.h"
)
qt5_add_dbus_interface(keepassx_SOURCES
quickunlock/dbus/org.freedesktop.PolicyKit1.Authority.xml
polkit_dbus
)

find_library(KEYUTILS_LIBRARIES NAMES keyutils)
if(NOT KEYUTILS_LIBRARIES)
message(FATAL_ERROR "Could not find libkeyutils")
endif()
endif()
if(WIN32)
set(keepassx_SOURCES
${keepassx_SOURCES}
gui/osutils/winutils/ScreenLockListenerWin.cpp
gui/osutils/winutils/WinUtils.cpp)
if (MSVC)
list(APPEND keepassx_SOURCES winhello/WindowsHello.cpp)
list(APPEND keepassx_SOURCES quickunlock/WindowsHello.cpp)
endif()
endif()

Expand Down Expand Up @@ -315,9 +337,9 @@ if(WITH_XC_NETWORKING)
endif()

if(APPLE)
list(APPEND keepassx_SOURCES touchid/TouchID.mm)
list(APPEND keepassx_SOURCES quickunlock/TouchID.mm)
# TODO: Remove -Wno-error once deprecation warnings have been resolved.
set_source_files_properties(touchid/TouchID.mm PROPERTY COMPILE_FLAGS "-Wno-old-style-cast")
set_source_files_properties(quickunlock/TouchID.mm PROPERTY COMPILE_FLAGS "-Wno-old-style-cast")
endif()

configure_file(config-keepassx.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-keepassx.h)
Expand All @@ -343,6 +365,7 @@ target_link_libraries(keepassx_core
${ZXCVBN_LIBRARIES}
${ZLIB_LIBRARIES}
${ARGON2_LIBRARIES}
${KEYUTILS_LIBRARIES}
${thirdparty_LIBRARIES}
)

Expand Down
13 changes: 13 additions & 0 deletions src/core/Database.cpp
Expand Up @@ -113,6 +113,8 @@ bool Database::open(QSharedPointer<const CompositeKey> key, QString* error)
* Unless `readOnly` is set to false, the database will be opened in
* read-write mode and fall back to read-only if that is not possible.
*
* If key is provided as null, only headers will be read.
*
* @param filePath path to the file
* @param key composite key for unlocking the database
* @param error error message in case of failure
Expand Down Expand Up @@ -996,3 +998,14 @@ void Database::stopModifiedTimer()
{
QMetaObject::invokeMethod(&m_modifiedTimer, "stop");
}

QUuid Database::publicUuid()
{

if (!publicCustomData().contains("KPXC_PUBLIC_UUID")) {
publicCustomData().insert("KPXC_PUBLIC_UUID", QUuid::createUuid().toRfc4122());
markAsModified();
}

return QUuid::fromRfc4122(publicCustomData()["KPXC_PUBLIC_UUID"].toByteArray());
}
1 change: 1 addition & 0 deletions src/core/Database.h
Expand Up @@ -102,6 +102,7 @@ class Database : public ModifiableObject
bool hasNonDataChanges() const;
bool isSaving();

QUuid publicUuid();
QUuid uuid() const;
QString filePath() const;
QString canonicalFilePath() const;
Expand Down
9 changes: 9 additions & 0 deletions src/format/KdbxReader.cpp
Expand Up @@ -27,6 +27,8 @@
/**
* Read KDBX magic header numbers from a device.
*
* Passing a null key will only read in the unprotected headers.
*
* @param device input device
* @param sig1 KDBX signature 1
* @param sig2 KDBX signature 2
Expand Down Expand Up @@ -55,6 +57,8 @@ bool KdbxReader::readMagicNumbers(QIODevice* device, quint32& sig1, quint32& sig
* Read KDBX stream from device.
* The device will automatically be reset to 0 before reading.
*
* Passing a null key will only read in the unprotected headers.
*
* @param device input device
* @param key database encryption composite key
* @param db database to read into
Expand Down Expand Up @@ -91,6 +95,11 @@ bool KdbxReader::readDatabase(QIODevice* device, QSharedPointer<const CompositeK
return false;
}

// No key provided - don't proceed to load payload
if (key.isNull()) {
return true;
}

// read payload
return readDatabaseImpl(device, headerStream.storedData(), std::move(key), db);
}
Expand Down
16 changes: 2 additions & 14 deletions src/gui/ApplicationSettingsWidget.cpp
Expand Up @@ -29,15 +29,10 @@
#include "gui/Icons.h"
#include "gui/MainWindow.h"
#include "gui/osutils/OSUtils.h"
#include "quickunlock/QuickUnlockInterface.h"

#include "FileDialog.h"
#include "MessageBox.h"
#ifdef Q_OS_MACOS
#include "touchid/TouchID.h"
#endif
#ifdef Q_CC_MSVC
#include "winhello/WindowsHello.h"
#endif

class ApplicationSettingsWidget::ExtraPage
{
Expand Down Expand Up @@ -314,14 +309,7 @@ void ApplicationSettingsWidget::loadSettings()
m_secUi->EnableCopyOnDoubleClickCheckBox->setChecked(
config()->get(Config::Security_EnableCopyOnDoubleClick).toBool());

bool quickUnlockAvailable = false;
#if defined(Q_OS_MACOS)
quickUnlockAvailable = TouchID::getInstance().isAvailable();
#elif defined(Q_CC_MSVC)
quickUnlockAvailable = getWindowsHello()->isAvailable();
connect(getWindowsHello(), &WindowsHello::availableChanged, m_secUi->quickUnlockCheckBox, &QCheckBox::setEnabled);
#endif
m_secUi->quickUnlockCheckBox->setEnabled(quickUnlockAvailable);
m_secUi->quickUnlockCheckBox->setEnabled(getQuickUnlock()->isAvailable());
m_secUi->quickUnlockCheckBox->setChecked(config()->get(Config::Security_QuickUnlock).toBool());

for (const ExtraPage& page : asConst(m_extraPages)) {
Expand Down

0 comments on commit a5a4c16

Please sign in to comment.