diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml
index 56cc1e89214..c8d84e484c9 100644
--- a/lib/thirdpartylibs.xml
+++ b/lib/thirdpartylibs.xml
@@ -737,7 +737,7 @@ All rights reserved.
webauthn
WebAuthn
- 2.1.1
+ 2.2.2
MIT
https://github.com/lbuchs/WebAuthn
diff --git a/lib/webauthn/README.md b/lib/webauthn/README.md
index 0fa46c34457..8d1cb7baac4 100644
--- a/lib/webauthn/README.md
+++ b/lib/webauthn/README.md
@@ -19,7 +19,8 @@ See /_test for a simple usage of this library. Check [webauthn.lubu.ch](https://
* packed ✅
* tpm ✅
-This library supports authenticators which are signed with a X.509 certificate or which are self attested. ECDAA is not supported.
+> [!NOTE]
+> This library supports authenticators which are signed with a X.509 certificate or which are self attested. ECDAA is not supported.
## Workflow
@@ -60,39 +61,44 @@ their organization.
### no attestation
just verify that the device is the same device used on registration.
You can use 'none' attestation with this library if you only check 'none' as format.
-* this is propably what you want to use if you want simple 2FA login protection like github, facebook, google, etc.
+
+> [!TIP]
+> this is propably what you want to use if you want secure login for a public website.
### indirect attestation
the browser may replace the AAGUID and attestation statement with a more privacy-friendly and/or more easily
verifiable version of the same data (for example, by employing an anonymization CA).
You can not validate against any root ca, if the browser uses a anonymization certificate.
this library sets attestation to indirect, if you select multiple formats but don't provide any root ca.
-* hybrid soultion, clients may be discouraged by browser warnings but then you know what device they're using (statistics rulez!)
+
+> [!TIP]
+> hybrid soultion, clients may be discouraged by browser warnings but then you know what device they're using (statistics rulez!)
### direct attestation
the browser proviedes data about the identificator device, the device can be identified uniquely. User could be tracked over multiple sites, because of that the browser may show a warning message about providing this data when register.
this library sets attestation to direct, if you select multiple formats and provide root ca's.
-* this is probably what you want if you know what devices your clients are using and make sure that only this devices are used.
-## Client-side discoverable Credentials
+> [!TIP]
+> this is probably what you want if you know what devices your clients are using and make sure that only this devices are used.
+
+## Passkeys / Client-side discoverable Credentials
A Client-side discoverable Credential Source is a public key credential source whose credential private key is stored in the authenticator,
client or client device. Such client-side storage requires a resident credential capable authenticator.
This is only supported by FIDO2 hardware, not by older U2F hardware.
+>[!NOTE]
+>Passkeys is a technique that allows sharing credentials stored on the device with other devices. So from a technical standpoint of the server, there is no difference to client-side discoverable credentials. The difference is only that the phone or computer system is automatically syncing the credentials between the user’s devices via a cloud service. The cross-device sync of passkeys is managed transparently by the OS.
+
### How does it work?
-In a typical **server-side key** process, the user provides their username (and sometimes password)
-and the server responds with a list of all the public key credential identifiers that the user has registered.
-The authenticator then selects the first credential identifier it issued and responds with a signature
-that can be verified using the public key registered during the registration process.
+In a typical server-side key management process, a user initiates a request by entering their username and, in some cases, their password.
+The server validates the user's credentials and, upon successful authentication, retrieves a list of all public key identifiers associated with that user account.
+This list is then returned to the authenticator, which selects the first credential identifier it issued and responds with a signature that can be verified using the public key registered during the registration process.
In a client-side key process, the user does not need to provide a username or password.
-Instead, the authenticator searches its own memory to see if it has saved a key for the relying party.
+Instead, the authenticator searches its own memory to see if it has saved a key for the relying party (domain).
If a key is found, the authentication process proceeds in the same way as it would if the server had sent a list
of identifiers. There is no difference in the verification process.
-Both Apple and Windows 10/11 (with Firefox and Chromium) support Resident Credential.
-However, older operating systems such as Windows 7 do not support it and instead fall back to using FIDO U2F.
-
### How can I use it with this library?
#### on registration
When calling `WebAuthn\WebAuthn->getCreateArgs`, set `$requireResidentKey` to true,
@@ -100,21 +106,16 @@ to notify the authenticator that he should save the registration in its memory.
#### on login
When calling `WebAuthn\WebAuthn->getGetArgs`, don't provide any `$credentialIds` (the authenticator will look up the ids in its own memory and returns the user ID as userHandle).
+Set the type of authenticator to `hybrid` (Passkey scanned via QR Code) and `internal` (Passkey stored on the device itself).
#### disadvantage
The RP ID (= domain) is saved on the authenticator. So If an authenticator is lost, its theoretically possible to find the services, which the authenticator is used and login there.
-## Passkeys
-Passkeys is a technique that allows sharing credentials stored on the device with other devices. So from a technical standpoint of the server,
-there is no difference to client-side discoverable credentials. The difference is only that the phone or computer system is automatically
-syncing the credentials between the user’s devices via a cloud service. The cross-device sync of passkeys is managed transparently by the OS.
-
-### Browser support
+### device support
Availability of built-in passkeys that automatically synchronize to all of a user’s devices: (see also [passkeys.dev/device-support](https://passkeys.dev/device-support/))
-* Apple: iOS 16 / iPadOS 16 / macOS Ventura
-* Google: support in Android starting October 2022
-* Microsoft Windows is set to deliver support in 2023.
-* Firefox see [Bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1792433)
+* Apple iOS 16+ / iPadOS 16+ / macOS Ventura+
+* Android 9+
+* Microsoft Windows 11 23H2+
## Requirements
* PHP >= 8.0 with [OpenSSL](http://php.net/manual/en/book.openssl.php) and [Multibyte String](https://www.php.net/manual/en/book.mbstring.php)
diff --git a/lib/webauthn/readme_moodle.txt b/lib/webauthn/readme_moodle.txt
index e0615ecbde7..7d991bf454a 100644
--- a/lib/webauthn/readme_moodle.txt
+++ b/lib/webauthn/readme_moodle.txt
@@ -1,5 +1,6 @@
-WebAuthn 2.0.1
+WebAuthn
--------------
+
https://github.com/lbuchs/WebAuthn
Instructions to import WebAuthn into Moodle:
diff --git a/lib/webauthn/src/Attestation/AuthenticatorData.php b/lib/webauthn/src/Attestation/AuthenticatorData.php
index 0a9eec8cf46..83462b12e5e 100644
--- a/lib/webauthn/src/Attestation/AuthenticatorData.php
+++ b/lib/webauthn/src/Attestation/AuthenticatorData.php
@@ -189,6 +189,24 @@ class AuthenticatorData {
return $this->_flags->userVerified;
}
+ /**
+ * returns true if the backup is eligible
+ * @return boolean
+ */
+ public function getIsBackupEligible()
+ {
+ return $this->_flags->isBackupEligible;
+ }
+
+ /**
+ * returns true if the current credential is backed up
+ * @return boolean
+ */
+ public function getIsBackup()
+ {
+ return $this->_flags->isBackup;
+ }
+
// -----------------------------------------------
// PRIVATE
// -----------------------------------------------
@@ -259,6 +277,8 @@ class AuthenticatorData {
// named flags
$flags->userPresent = $flags->bit_0;
$flags->userVerified = $flags->bit_2;
+ $flags->isBackupEligible = $flags->bit_3;
+ $flags->isBackup = $flags->bit_4;
$flags->attestedDataIncluded = $flags->bit_6;
$flags->extensionDataIncluded = $flags->bit_7;
return $flags;
diff --git a/lib/webauthn/src/Attestation/Format/FormatBase.php b/lib/webauthn/src/Attestation/Format/FormatBase.php
index 765af85d582..92f1010b409 100644
--- a/lib/webauthn/src/Attestation/Format/FormatBase.php
+++ b/lib/webauthn/src/Attestation/Format/FormatBase.php
@@ -89,7 +89,7 @@ abstract class FormatBase {
/**
* creates a PEM encoded chain file
- * @return type
+ * @return string|null
*/
protected function _createX5cChainFile() {
$content = '';
diff --git a/lib/webauthn/src/WebAuthn.php b/lib/webauthn/src/WebAuthn.php
index 0da0aa64e6d..2d08a690fc4 100644
--- a/lib/webauthn/src/WebAuthn.php
+++ b/lib/webauthn/src/WebAuthn.php
@@ -30,6 +30,7 @@ class WebAuthn {
private $_signatureCounter;
private $_caFiles;
private $_formats;
+ private $_androidKeyHashes;
/**
* Initialize a new WebAuthn server
@@ -90,6 +91,23 @@ class WebAuthn {
}
}
+ /**
+ * add key hashes for android verification
+ * @param array $hashes
+ * @return void
+ */
+ public function addAndroidKeyHashes($hashes) {
+ if (!\is_array($this->_androidKeyHashes)) {
+ $this->_androidKeyHashes = [];
+ }
+
+ foreach ($hashes as $hash) {
+ if (is_string($hash)) {
+ $this->_androidKeyHashes[] = $hash;
+ }
+ }
+ }
+
/**
* Returns the generated challenge to save for later validation
* @return ByteBuffer
@@ -397,6 +415,8 @@ class WebAuthn {
$data->rootValid = $rootValid;
$data->userPresent = $userPresent;
$data->userVerified = $userVerified;
+ $data->isBackupEligible = $attestationObject->getAuthenticatorData()->getIsBackupEligible();
+ $data->isBackedUp = $attestationObject->getAuthenticatorData()->getIsBackup();
return $data;
}
@@ -601,6 +621,10 @@ class WebAuthn {
* @throws WebAuthnException
*/
private function _checkOrigin($origin) {
+ if (str_starts_with($origin, 'android:apk-key-hash:')) {
+ return $this->_checkAndroidKeyHashes($origin);
+ }
+
// https://www.w3.org/TR/webauthn/#rp-id
// The origin's scheme must be https
@@ -617,6 +641,19 @@ class WebAuthn {
return \preg_match('/' . \preg_quote($this->_rpId) . '$/i', $host) === 1;
}
+ /**
+ * checks if the origin value contains a known android key hash
+ * @param string $origin
+ * @return boolean
+ */
+ private function _checkAndroidKeyHashes($origin) {
+ $parts = explode('android:apk-key-hash:', $origin);
+ if (count($parts) !== 2) {
+ return false;
+ }
+ return in_array($parts[1], $this->_androidKeyHashes, true);
+ }
+
/**
* generates a new challange
* @param int $length