Ошибка проверки подписи утверждения пароля на iOS

Я пытаюсь проверить подпись, полученную из запроса на подтверждение, но безуспешно. Вот объекты, которые я получаю от клиента, аттестация и утверждение соответственно:

const attestationChallenge = 'p58vEOB1TJ0Rh3PSwyTKnujxmYYQmGka20bYBK8hw8sfL/2btBbNeSmIiycTsvFfEgGzp7X5JVkpW4FMer6mcT5DOcgfh10OGXUdFe51exz/mOuj7+TRIxQNcaJ0jv/QTT9kCvTRydo2ntP2gsf2oVnVH+nweTEG4iY9GNFwDcU=';

const attestation = {
    id: 'XT39NMONrxoh29HHmyh35qwaS1o=',
    rawId: 'XT39NMONrxoh29HHmyh35qwaS1o=',
    response: {
        clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoicDU4dkVPQjFUSjBSaDNQU3d5VEtudWp4bVlZUW1Ha2EyMGJZQks4aHc4c2ZMXzJidEJiTmVTbUlpeWNUc3ZGZkVnR3pwN1g1SlZrcFc0Rk1lcjZtY1Q1RE9jZ2ZoMTBPR1hVZEZlNTFleHpfbU91ajctVFJJeFFOY2FKMGp2X1FUVDlrQ3ZUUnlkbzJudFAyZ3NmMm9WblZILW53ZVRFRzRpWTlHTkZ3RGNVIiwib3JpZ2luIjoiaHR0cHM6Ly90bXB0ZXN0NTU1LmJsb2Nrc29mdGxhYi5jb20ifQ==',
        attestationObject: 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViY85atP17k4jCSodKGG3KumgFtv9mzmvanMjekolX24mVdAAAAAPv8MAcVTk7MjAtuAgVX170AFF09/TTDja8aIdvRx5sod+asGktapQECAyYgASFYIHSvWI6jrp0v03xk2GzDDnMFD3hkZ+Vu4IFvXLPBNUDLIlgg8E4TIs8fiErLT7nEeOI6gjb+zTsKSQjPi6bplGD4djA='
    }
};

const assertionChallenge = 'ECJ3xtuY4U71MEZyjRa8pKcFBPXkRORXkzNe43P-OpdITVirSPjpn9aTzfFUOM0Gd9yR-KI82RRkK0_nei-2zy0HXVSDvfQXwLsIZmXBY7uuwSEaDEB5G57fc3B3Uu1bv8tjLSsdpzp5BNSi5kWNIcImwTVmAyeeNXuKp8ZPhbs';

const assertion = {
    id: 'ibYKqMzdLS3eEYNZKzoYBuPHNlY=',
    rawId: 'ibYKqMzdLS3eEYNZKzoYBuPHNlY=',
    response: {
        clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiRUNKM3h0dVk0VTcxTUVaeWpSYThwS2NGQlBYa1JPUlhrek5lNDNQLU9wZElUVmlyU1BqcG45YVR6ZkZVT00wR2Q5eVItS0k4MlJSa0swX25laS0yenkwSFhWU0R2ZlFYd0xzSVptWEJZN3V1d1NFYURFQjVHNTdmYzNCM1V1MWJ2OHRqTFNzZHB6cDVCTlNpNWtXTkljSW13VFZtQXllZU5YdUtwOFpQaGJzIiwib3JpZ2luIjoiaHR0cHM6Ly90bXB0ZXN0NTU1LmJsb2Nrc29mdGxhYi5jb20ifQ==',
        authenticatorData: '85atP17k4jCSodKGG3KumgFtv9mzmvanMjekolX24mUdAAAAAA==',
        signature: 'MEUCIQCAJrsIKKXp7Fmw8jVzxH5eLVTZqSpx0OihDtGCbZ5/ywIgYH48xfQlAA6+lY0NjWsHa7+vwEzmGwEOU132zwAOYTo=',
        userHandle: 'SmU2Qm9NaDM3dW5sQVFUNU5FVGllZw=='
    }
};

Вот декодированный JWK открытого ключа:

{
  "kty": "EC",
  "alg": "ES256",
  "crv": "P-256",
  "x": "dK9YjqOunS/TfGTYbMMOcwUPeGRn5W7ggW9cs8E1QMs = ",
  "y": "8E4TIs8fiErLT7nEeOI6gjb+zTsKSQjPi6bplGD4djA = "
}

Я также заметил закономерность в подписях: все они начинаются с очень похожей структуры, обычно она начинается с ME и вскоре после этого содержит такие символы, как U, I, C и Q, но не так последовательно, как ME. Это наводит меня на мысль, что подпись начинается с некоторого стабильного хеша данных аутентификатора, как написано в спецификации , однако это применимо только к формату аттестации Apple, но формат, возвращаемый из запроса на аттестацию, отсутствует и пытается объединить вызов и данные аутентификатора, похоже, не помогают проверке работать.

Вот что я пробовал:

const authData = Buffer.from(assertion.response.authenticatorData, 'base64');

const { createHash, verify } = require('crypto');

const hash = createHash('sha256').update(Buffer.from(attestation.response.clientDataJSON, 'base64')).digest();

const concat = Buffer.concat([authData, hash]);

const result = verify(
  null,
  concat,
  { key, format: 'jwk' }, // the JWK above
  Buffer.from(assertion.response.signature, 'base64')
);

console.info(result);
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Со стороны attestation проверять нечего. Если мы проанализируем его, мы получим

{
  attStmt: {},
  authData: <Binary Data>,
  fmt: 'none'
}

А поскольку fmt есть none, вам нечем подтвердить эту часть. Это не всегда важно, проверка здесь будет подтверждать, что аутентификатор действительно соответствует тому типу, о котором он говорит.

Во второй части вы правы: имеющиеся у вас данные не проверят подпись. Теперь ваш код на первый взгляд кажется правильным, но если вы проверите идентификатор сгенерированного вами ключа, XT39NMONrxoh29HHmyh35qwaS1o=, он не соответствует ключу, использованному в утверждении, ibYKqMzdLS3eEYNZKzoYBuPHNlY=. Это означает, что для подписи использовался другой закрытый ключ, отличный от того, которому соответствует открытый ключ.

Вам нужно будет либо настроить, чтобы он использовал ключ, указанный выше в утверждении, либо вам нужно будет использовать открытый ключ, соответствующий тому, который использовался в утверждении.

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

Constantine 06.08.2024 13:57

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

Asthor 06.08.2024 14:00

Я также только что попытался вернуть список разрешенных учетных данных, и теперь он снова работает нормально (раньше говорилось, что учетные данные отсутствуют). Однако Android перестал работать и даже не отображает никаких серьезных ошибок в журнале. В настоящее время я изучаю эту проблему, подозревая, что она может быть связана с конфигурацией.

Constantine 06.08.2024 14:33

Другие вопросы по теме