64 lines
2.7 KiB
PHP
64 lines
2.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Webauthn\CeremonyStep;
|
|
|
|
use Webauthn\AuthenticationExtensions\AuthenticationExtensions;
|
|
use Webauthn\AuthenticatorAssertionResponse;
|
|
use Webauthn\AuthenticatorAttestationResponse;
|
|
use Webauthn\Exception\AuthenticatorResponseVerificationException;
|
|
use Webauthn\PublicKeyCredentialCreationOptions;
|
|
use Webauthn\PublicKeyCredentialRequestOptions;
|
|
use Webauthn\PublicKeyCredentialSource;
|
|
use Webauthn\U2FPublicKey;
|
|
use function is_string;
|
|
|
|
final class CheckRelyingPartyIdIdHash implements CeremonyStep
|
|
{
|
|
public function process(
|
|
PublicKeyCredentialSource $publicKeyCredentialSource,
|
|
AuthenticatorAssertionResponse|AuthenticatorAttestationResponse $authenticatorResponse,
|
|
PublicKeyCredentialRequestOptions|PublicKeyCredentialCreationOptions $publicKeyCredentialOptions,
|
|
?string $userHandle,
|
|
string $host
|
|
): void {
|
|
$authData = $authenticatorResponse instanceof AuthenticatorAssertionResponse ? $authenticatorResponse->authenticatorData : $authenticatorResponse->attestationObject->authData;
|
|
$C = $authenticatorResponse->clientDataJSON;
|
|
$attestedCredentialData = $publicKeyCredentialSource->getAttestedCredentialData();
|
|
$credentialPublicKey = $attestedCredentialData->credentialPublicKey;
|
|
$credentialPublicKey !== null || throw AuthenticatorResponseVerificationException::create(
|
|
'No public key available.'
|
|
);
|
|
$isU2F = U2FPublicKey::isU2FKey($credentialPublicKey);
|
|
$rpId = $publicKeyCredentialOptions->rpId ?? $publicKeyCredentialOptions->rp->id ?? $host;
|
|
$facetId = $this->getFacetId($rpId, $publicKeyCredentialOptions->extensions, $authData ->extensions);
|
|
$rpIdHash = hash('sha256', $isU2F ? $C->origin : $facetId, true);
|
|
hash_equals(
|
|
$rpIdHash,
|
|
$authData
|
|
->rpIdHash
|
|
) || throw AuthenticatorResponseVerificationException::create('rpId hash mismatch.');
|
|
}
|
|
|
|
private function getFacetId(
|
|
string $rpId,
|
|
AuthenticationExtensions $authenticationExtensionsClientInputs,
|
|
null|AuthenticationExtensions $authenticationExtensionsClientOutputs
|
|
): string {
|
|
if ($authenticationExtensionsClientOutputs === null || ! $authenticationExtensionsClientInputs->has(
|
|
'appid'
|
|
) || ! $authenticationExtensionsClientOutputs->has('appid')) {
|
|
return $rpId;
|
|
}
|
|
$appId = $authenticationExtensionsClientInputs->get('appid')
|
|
->value;
|
|
$wasUsed = $authenticationExtensionsClientOutputs->get('appid')
|
|
->value;
|
|
if (! is_string($appId) || $wasUsed !== true) {
|
|
return $rpId;
|
|
}
|
|
return $appId;
|
|
}
|
|
}
|