Laragear/WebAuthn

View on GitHub
src/Assertion/Validator/Pipes/CheckPublicKeySignature.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

namespace Laragear\WebAuthn\Assertion\Validator\Pipes;

use Closure;
use Laragear\WebAuthn\Assertion\Validator\AssertionValidation;
use Laragear\WebAuthn\Exceptions\AssertionException;
use OpenSSLAsymmetricKey;
use function base64_decode;
use function hash;
use function openssl_pkey_get_public;
use function openssl_verify;
use const OPENSSL_ALGO_SHA256;

/**
 * @internal
 */
class CheckPublicKeySignature
{
    /**
     * Handle the incoming Assertion Validation.
     *
     * @param  \Laragear\WebAuthn\Assertion\Validator\AssertionValidation  $validation
     * @param  \Closure  $next
     * @return mixed
     * @throws \Laragear\WebAuthn\Exceptions\AssertionException
     */
    public function handle(AssertionValidation $validation, Closure $next): mixed
    {
        $publicKey = openssl_pkey_get_public($validation->credential->public_key);

        if (!$publicKey) {
            throw AssertionException::make('Stored Public Key is invalid.');
        }

        $signature = base64_decode($validation->request->json('response.signature', ''));

        if (!$signature) {
            throw AssertionException::make('Signature is empty.');
        }

        $this->validateSignature($validation, $publicKey, $signature);

        return $next($validation);
    }

    /**
     * Validate the signature from the assertion.
     *
     * @param  \Laragear\WebAuthn\Assertion\Validator\AssertionValidation  $validation
     * @param  string  $signature
     * @param  \OpenSSLAsymmetricKey  $publicKey
     * @return void
     * @throws \Laragear\WebAuthn\Exceptions\AssertionException
     */
    public function validateSignature(
        AssertionValidation $validation,
        OpenSSLAsymmetricKey $publicKey,
        string $signature
    ): void {
        $verifiable = base64_decode($validation->request->json('response.authenticatorData'))
            .hash('sha256', base64_decode($validation->request->json('response.clientDataJSON')), true);

        if (openssl_verify($verifiable, $signature, $publicKey, OPENSSL_ALGO_SHA256) !== 1) {
            throw AssertionException::make('Signature is invalid.');
        }
    }
}