getAttestedCredentialData() ->credentialPublicKey; $credentialPublicKey !== null || throw AuthenticatorResponseVerificationException::create( 'No public key available.' ); $algorithms = array_map( fn ($pubKeyCredParam) => $pubKeyCredParam->alg, $publicKeyCredentialOptions->pubKeyCredParams ); if (count($algorithms) === 0) { $algorithms = [Algorithms::COSE_ALGORITHM_ES256, Algorithms::COSE_ALGORITHM_RS256]; } $coseKey = $this->getCoseKey($credentialPublicKey); in_array($coseKey->alg(), $algorithms, true) || throw AuthenticatorResponseVerificationException::create( sprintf('Invalid algorithm. Expected one of %s but got %d', implode(', ', $algorithms), $coseKey->alg()) ); } private function getCoseKey(string $credentialPublicKey): Key { $isU2F = U2FPublicKey::isU2FKey($credentialPublicKey); if ($isU2F === true) { $credentialPublicKey = U2FPublicKey::convertToCoseKey($credentialPublicKey); } $stream = new StringStream($credentialPublicKey); $credentialPublicKeyStream = Decoder::create()->decode($stream); $stream->isEOF() || throw AuthenticatorResponseVerificationException::create( 'Invalid key. Presence of extra bytes.' ); $stream->close(); $credentialPublicKeyStream instanceof Normalizable || throw AuthenticatorResponseVerificationException::create( 'Invalid attestation object. Unexpected object.' ); $normalizedData = $credentialPublicKeyStream->normalize(); is_array($normalizedData) || throw AuthenticatorResponseVerificationException::create( 'Invalid attestation object. Unexpected object.' ); /** @var array $normalizedData */ return Key::create($normalizedData); } }