github.com/go-webauthn/webauthn (поддерживаемый форк duo-labs/webauthn) проводит обе церемонии — BeginRegistration/FinishRegistration и BeginLogin/FinishLogin или их варианты Validate* для фреймворков помимо net/http — и проверяет все форматы аттестации. Проверка проводилась на тех же ответах программного аутентификатора, что и для SimpleWebAuthn, py_webauthn и WebAuthn4J.
Политика берётся из конфигурации и передаётся в SessionData. С пустым AuthenticatorSelection вызов BeginRegistration отправил пустой объект, поэтому браузеры применяют значения по умолчанию (проверка пользователя preferred, резидентный ключ discouraged), а при проверке принимались ответы со сброшенным флагом UV, потому что сессия требовала только preferred. Когда в сессии было задано UserVerification: required, тот же assertion отклонялся с ошибкой User verification required but flag not set by authenticator. Задайте политику в Config.AuthenticatorSelection, как в примере, и сохраняйте весь SessionData между двумя вызовами.
Обработка счётчика — самое важное отличие от других библиотек. Вход с assertion, у которого счётчик (3) меньше сохранённого (5), прошёл успешно: у возвращённых учётных данных был установлен Authenticator.CloneWarning, а SignCount остался равен 5. Библиотека лишь сообщает о возможном клоне; отказывать ли во входе, решает ваш код, и он должен проверять CloneWarning после каждого входа.
Подписи assertion должны быть в ASN.1 DER: подпись в формате raw r‖s длиной 64 байта отклонена с ошибкой Error validating the assertion signature: Signature invalid or not provided, а подпись DER с high-S прошла проверку. Список pubKeyCredParams по умолчанию длинный: ES256, ES384 и ES512 (-7, -35, -36), от RS256 до RS512 (от -257 до -259), от PS256 до PS512 (от -37 до -39) и Ed25519 (-8); учётные данные Ed25519 прошли сквозную проверку. Записи для ML-DSA в версии 0.18.2 нет.
Декодируйте то, что отправляет браузер, в инспекторе WebAuthn, определяйте модели аутентификаторов через поиск по AAGUID и пробуйте церемонии в песочнице ключей доступа.