Properly handle Windows Hello errors

The KeyCredentialManager::RequestCreateAsync call can fail because we can end up in a situation where Windows Hello is initially available but then becomes unavailable, such as during a remote desktop session. This commit prevents a crash by moving the call into the try-catch.

Fixes #7890

Also resets quick unlock if there is an unrecoverable error. This will not occur if the user merely canceled the Windows Hello dialog.
This commit is contained in:
Charlie Wang 2023-01-18 19:06:06 -05:00 committed by Jonathan White
parent cbbabf477a
commit 655202a35a
No known key found for this signature in database
GPG Key ID: 440FC65F2E0C6E01
3 changed files with 25 additions and 18 deletions

View File

@ -1531,10 +1531,6 @@ To prevent this error from appearing, you must go to "Database Settings / S
<source>Retry with empty password</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to authenticate with Windows Hello</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to authenticate with Touch ID</source>
<translation type="unfinished"></translation>
@ -1601,6 +1597,10 @@ If you do not have a key file, please leave the field empty.</source>
<source>authenticate to access the database</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to authenticate with Windows Hello: %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DatabaseSettingWidgetMetaData</name>

View File

@ -341,7 +341,12 @@ QSharedPointer<CompositeKey> DatabaseOpenWidget::buildDatabaseKey()
#ifdef Q_CC_MSVC
if (!getWindowsHello()->getKey(m_filename, keyData)) {
// Failed to retrieve Quick Unlock data
m_ui->messageWidget->showMessage(tr("Failed to authenticate with Windows Hello"), MessageWidget::Error);
auto error = getWindowsHello()->errorString();
if (!error.isEmpty()) {
m_ui->messageWidget->showMessage(tr("Failed to authenticate with Windows Hello: %1").arg(error),
MessageWidget::Error);
resetQuickUnlock();
}
return {};
}
#elif defined(Q_OS_MACOS)

View File

@ -64,22 +64,24 @@ namespace
array_view<uint8_t>(reinterpret_cast<uint8_t*>(challenge.data()), challenge.size()));
return AsyncTask::runAndWaitForFuture([&] {
// The first time this is used a key-pair will be generated using the common name
auto result =
KeyCredentialManager::RequestCreateAsync(s_winHelloKeyName, KeyCredentialCreationOption::FailIfExists)
.get();
if (result.Status() == KeyCredentialStatus::CredentialAlreadyExists) {
result = KeyCredentialManager::OpenAsync(s_winHelloKeyName).get();
} else if (result.Status() != KeyCredentialStatus::Success) {
error = QObject::tr("Failed to create Windows Hello credential.");
return false;
}
try {
// The first time this is used a key-pair will be generated using the common name
auto result = KeyCredentialManager::RequestCreateAsync(s_winHelloKeyName,
KeyCredentialCreationOption::FailIfExists)
.get();
if (result.Status() == KeyCredentialStatus::CredentialAlreadyExists) {
result = KeyCredentialManager::OpenAsync(s_winHelloKeyName).get();
} else if (result.Status() != KeyCredentialStatus::Success) {
error = QObject::tr("Failed to create Windows Hello credential.");
return false;
}
const auto signature = result.Credential().RequestSignAsync(challengeBuffer).get();
if (signature.Status() != KeyCredentialStatus::Success) {
error = QObject::tr("Failed to sign challenge using Windows Hello.");
if (signature.Status() != KeyCredentialStatus::UserCanceled) {
error = QObject::tr("Failed to sign challenge using Windows Hello.");
}
return false;
}