MDL-84175 libraries: Upgrade WebAuthn to 2.2.0

Signed-off-by: Daniel Ziegenberg <[email protected]>
This commit is contained in:
Daniel Ziegenberg
2025-05-06 06:34:57 +02:00
parent 8cb5d000a1
commit fb3121a49c
6 changed files with 85 additions and 26 deletions
+1 -1
View File
@@ -737,7 +737,7 @@ All rights reserved.</copyright>
<library>
<location>webauthn</location>
<name>WebAuthn</name>
<version>2.1.1</version>
<version>2.2.2</version>
<license>MIT</license>
<repository>https://github.com/lbuchs/WebAuthn</repository>
</library>
+24 -23
View File
@@ -19,7 +19,8 @@ See /_test for a simple usage of this library. Check [webauthn.lubu.ch](https://
* packed &#x2705;
* tpm &#x2705;
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 users 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 users 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 users 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)
+2 -1
View File
@@ -1,5 +1,6 @@
WebAuthn 2.0.1
WebAuthn
--------------
https://github.com/lbuchs/WebAuthn
Instructions to import WebAuthn into Moodle:
@@ -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;
@@ -89,7 +89,7 @@ abstract class FormatBase {
/**
* creates a PEM encoded chain file
* @return type
* @return string|null
*/
protected function _createX5cChainFile() {
$content = '';
+37
View File
@@ -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<string> $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