diff --git a/src/Service/AuthenticatorStatusValidator.php b/src/Service/AuthenticatorStatusValidator.php index d8132249..26660726 100644 --- a/src/Service/AuthenticatorStatusValidator.php +++ b/src/Service/AuthenticatorStatusValidator.php @@ -30,6 +30,11 @@ class AuthenticatorStatusValidator * @var string[] */ private readonly array $allowedStatus; + /** + * @var string[] + */ + private readonly array $deniedStatus; + public function __construct() { @@ -44,6 +49,13 @@ public function __construct() AuthenticatorStatus::FIDO_CERTIFIED_L2plus, AuthenticatorStatus::FIDO_CERTIFIED_L3plus, ]; + $this->deniedStatus = [ + AuthenticatorStatus::REVOKED, + AuthenticatorStatus::ATTESTATION_KEY_COMPROMISE, + AuthenticatorStatus::USER_KEY_PHYSICAL_COMPROMISE, + AuthenticatorStatus::USER_KEY_REMOTE_COMPROMISE, + AuthenticatorStatus::USER_VERIFICATION_BYPASS + ]; } /** @@ -57,6 +69,9 @@ public function validate(array $statusReports): void $meetsRequirement = false; $reportsProcessed = 0; $reportLog = []; + /* The status of the attestation can be multivalued, containing both a certification as a revocation. + First test for valid certification, then for reasons to deny + */ foreach ($statusReports as $report) { if (in_array($report->status, $this->allowedStatus)) { $meetsRequirement = true; @@ -64,11 +79,19 @@ public function validate(array $statusReports): void $reportsProcessed++; $reportLog[] = $report->status; } + if ($meetsRequirement) { + foreach ($statusReports as $report) { + if (in_array($report->status, $this->deniedStatus)) { + $meetsRequirement = false; + } + } + } if (!$meetsRequirement) { throw new AuthenticatorStatusNotSupportedException( sprintf( - 'Of the %d StatusReports tested, none met one of the required FIDO Certified statuses. ' . + 'Of the %d StatusReports tested, none met one of the required FIDO Certified statuses, + or the status was explicitly denied. ' . 'Reports tested: "%s"', $reportsProcessed, implode(', ', $reportLog) diff --git a/tests/Service/AuthenticatorStatusValidatorTest.php b/tests/Service/AuthenticatorStatusValidatorTest.php index 2923eb6c..10f9c8aa 100644 --- a/tests/Service/AuthenticatorStatusValidatorTest.php +++ b/tests/Service/AuthenticatorStatusValidatorTest.php @@ -82,6 +82,7 @@ public function invalidReports() 'invalid UPDATE_AVAILABLE' => [[$this->createReport(AuthenticatorStatus::UPDATE_AVAILABLE)]], 'invalid REVOKED' => [[$this->createReport(AuthenticatorStatus::REVOKED)]], 'invalid mixed, all bad' => [[$this->createReport(AuthenticatorStatus::UPDATE_AVAILABLE), $this->createReport(AuthenticatorStatus::NOT_FIDO_CERTIFIED)]], + 'invalid FIDO_CERTIFIED and REVOKED' => [[$this->createReport(AuthenticatorStatus::REVOKED), $this->createReport(AuthenticatorStatus::FIDO_CERTIFIED)]], ]; } final public const USER_VERIFICATION_BYPASS = '';