Рассчитать хеш для проверки подписи в webauthn

Я пытаюсь реализовать webauthn, но не могу заставить работать проверку подписи. Согласно https://w3c.github.io/webauthn/#verifying-assertion Я должен проверить подпись по следующим данным:

authData || sha256 (clientDataJSON)

AuthData и хэш sha256 должны быть «двоично объединены». Я понятия не имею, что именно они имеют в виду, но предполагаю, что они просто имеют в виду поставить байты рядом друг с другом, хотя понятия не имею, что именно будет «двоичным» в этом отношении.

Итак, учитывая аттестацию PublicKeyCredential с именем, я могу сгенерировать данные, на основе которых создается подпись, следующим образом:

var auth_data = new Uint8Array(attestation.response.authenticatorData);
var data_hash = sha256(new Uint8Array(attestation.response.clientDataJSON));
var signed    = new Uint8Array(auth_data.length + data_hash.length);

signed.set(auth_data);
signed.set(data_hash, auth_data.length);

Я, конечно, пробовал проверить это «подписанное» значение напрямую, и я тоже пробовал его хешировать. Ни один из них не подтверждает. Что я делаю неправильно при вычислении подписанных данных?

У меня есть эквивалентный код на стороне сервера (на C ++), где я создаю то же значение, а затем проверяю его с помощью OpenSSL. Этот подписанный расчет предназначен только для того, чтобы показать, что я делаю - я, конечно, не буду доверять этому значению на стороне сервера.


person Martijn Otto    schedule 11.02.2019    source источник
comment
Та же проблема здесь - это Gist, который показывает мою попытку сделать то же самое, что и выше. Вставьте код в консоль для запуска: gist.github.com/philholden/50120652bfe0498958fd5926694ba0498958fd5926694ba3   -  person Phil Holden    schedule 12.05.2021


Ответы (2)


Предполагая, что по опубликованной вами ссылке вы пытаетесь создать подпись утверждения. Я нашел это в документах -

Пусть подпись будет подписью утверждения конкатенационного аутентификатора Data || хэш с использованием privateKey selectedCredential, как показано на рисунке 4 ниже. Здесь безопасно использовать простую неограниченную конкатенацию, потому что данные аутентификатора описывают свою собственную длину. Хеш сериализованных клиентских данных (которые потенциально могут иметь переменную длину) всегда является последним элементом.

посмотрите на изображение ниже Пункт 11

Я думаю, что правильным способом было бы использовать сериализованную строку JSON AuthData и добавить ее в Client Data Hash и подписать ее с помощью закрытого ключа. На стороне сервера вы можете попытаться воссоздать ту же структуру и проверить ее с помощью открытого ключа.

Я не знаю о C ++, но в python вы можете использовать пакет под названием криптография и проверять подпись следующим образом:

>>> public_key.verify(
...     signature,
...     message,
...     padding.PSS(
...         mgf=padding.MGF1(hashes.SHA256()),
...         salt_length=padding.PSS.MAX_LENGTH
...     ),
...     hashes.SHA256()
... )
person Laksh Matai    schedule 12.07.2019

Формат подписи authenticatorData || clientDataJSONHash предназначен только для подписей подтверждения (аутентификации), а navigator.credentials.create() возвращает подпись подтверждения (регистрации). Ваш код должен работать для проверки navigator.credentials.get() ответов, но не .create().

Аттестационные подписи, как правило, не подписываются вновь созданным личный ключ учетных данных, но с закрытый ключ аттестации. Кроме того, формат подписанных данных и процедура их проверки определяется формат утверждения аттестации. Это сделано для того, чтобы уже существующее оборудование могло поддерживать генерацию подписей только определенным образом, поэтому эти различные форматы аттестации позволяют этим аппаратным реализациям работать с WebAuthn без обновления оборудования или прошивки.

Проверка подписи аттестации всегда требует анализа CBOR в заявление об аттестации и данные аутентификатора . Это связано с тем, что подпись доставляется в объекте аттестации с кодировкой CBOR, а открытый ключ учетных данных доставляется в данных аутентификатора. Хотя credential.response.getPublicKey() также возвращает тот же открытый ключ учетных данных, это представление его не подписано. Данные аутентификатора покрыты подписью, поэтому открытый ключ учетных данных должен быть извлекается из данных аутентификатора, чтобы подпись имела смысл.

Если ваше приложение не заботится об аттестации, вы можете просто не проверять подпись аттестации и вместо этого проверять только будущие подписи утверждения. Вы по-прежнему можете хранить объект аттестации на случай, если вы передумаете и захотите позаботиться об аттестации в будущем.

person Emil Lundberg    schedule 12.05.2021