Машинний переклад, не перевірений носієм мови. Еталоном є англійська версія.

Довіра до приймача та морська галузьРедагувати на GitHubДжерело: docs/OSNMA.md

Верифікатор OSNMA для Galileo на боці приймача

Верифікатор на боці приймача для автентифікації навігаційних повідомлень відкритого сервісу Galileo (OSNMA), написаний чистим Rust. Він читає сторінки I/NAV і повідомляє для кожного супутника та кожної епохи, чи навігаційні дані криптографічно автентифіковані, і чому перевірка не пройшла.

Лише консультативно. Це результат аналізу та моніторингу, а не навігаційне обладнання із затвердженням типу. Статус автентифікації, який тут повідомляється, не є послугою цілісності навігації і не можна використовувати як єдину підставу для будь-якого навігаційного рішення або рішення щодо безпеки.

ПОВІДОМЛЕННЯ: інтелектуальна власність в інтерфейсі Galileo OSNMA#

Kshana не надає жодних прав на інтелектуальну власність Європейського Союзу в документі керування інтерфейсом сигналу в просторі Galileo OSNMA («ICD IPR»). ICD має власне дозвіл (його додаток E), який є невиключним і безоплатним і має власні умови, обсяг і обмеження. Той, хто використовує, будує чи поширює програмне забезпечення на основі цього модуля, покладається безпосередньо на цей дозвіл і має сам прочитати та прийняти його умови. Ліцензія Kshana (AGPL-3.0-only або комерційна ліцензія) охоплює лише власний код Kshana.

Цей модуль реалізує алгоритми, які описують наведені нижче документи. Текст ICD не відтворюється; числові значення (розкладки полів, перелічення, таблиця пошуку MAC) переформульовано власною нотацією Kshana з посиланням на джерело в коді. ICD і Керівні настанови для приймачів © Європейський Союз; джерело тут зазначено. Kshana не розробляється, не використовується, не схвалюється і не підтримується Європейським Союзом, Європейською комісією, EUSPA чи будь-яким іншим органом.

Довідкові документи#

Опубліковано Європейським центром послуг GNSS.

Документ Версія Дата
Galileo OSNMA Signal-in-Space ICD («SIS ICD») Видання 1,1 жовтень 2023
Galileo OSNMA Receiver Guidelines Видання 1,3 січень 2024

Номери розділів і таблиць, які цитуються в коді та тут, стосуються цих версій.

Що перевіряється#

Ланцюг довіри від кореня до даних:

  1. Відкритий ключ (ICD 3.2.2, 6,2). DSM-PKR збирається з його блоків, а його шлях Меркла проходиться до довіреного кореня Меркла (SHA-256).
  2. KROOT (ICD 3.2.3, 6,3). DSM-KROOT збирається; його підпис ECDSA (P-256/SHA-256 або P-521/SHA-512) перевіряється за відкритим ключем, який він називає, над заголовком NMA та параметрами ланцюга.
  3. Ключі TESLA (ICD 5,5, 6,4). Кожен ключ у повідомленні MACK простежується назад до KROOT або до раніше перевіреного ключа за допомогою хеш-функції ланцюга.
  4. MACSEQ (ICD 4.1.2, 6,6). Гнучкі поля Tag-Info перевіряються за MACSEQ ключем, що відкриває цей MACK.
  5. Теги (ICD 4,2, 6,7). Кожен тег перераховується (HMAC-SHA-256 або CMAC-AES, усічені до довжини тега ланцюга) над ідентифікаторами супутників, часом підкадру, позицією тега, статусом NMA та навігаційними даними, які він охоплює, і порівнюється. Обробляються ADKD 0 (ефемериди, годинник і стан), ADKD 4 (параметри часу) і ADKD 12 (повільний MAC, ключ опубліковано через десять підкадрів), із перехресною автентифікацією супутників, які самі не несуть OSNMA, і фіктивними тегами (COP 0).

Тег, що називає зарезервоване значення або чий ADKD не збігається зі слотом таблиці пошуку MAC, відкладається (Керівні настанови для приймачів кажуть його відкинути) і повідомляється як discarded, а не як відмова.

Сторінки перевіряються за їхнім CRC (CRC-24Q Galileo) перед усім іншим; сторінка, що не пройшла, відкидається та повідомляється (bad_crc).

Значення статусу#

Для кожного тега: authenticated, failed з причиною (tag_mismatch, macseq_mismatch, key_chain_mismatch, key_conflict), pending з причиною (no_chain, awaiting_key, no_nav_data, unknown_maclt, unsupported_function, service_not_usable, chain_mismatch) або discarded. Фіктивний тег (COP 0) показується як authenticated на рівні тега, бо він доводить ключ, але не охоплює жодних навігаційних даних і ніколи не враховується для супутника.

Для кожного супутника у вигляді, який споживає монітор receiver-trust:

  • Authenticated лише поки найновіші перевірені дані ефемерид і годинника (ADKD 0 або
    1. цього супутника свіжі (за замовчуванням у межах 600 с від часу верифікатора) і досі є даними, що використовуються. Перевіряються дані, а не IODnav: верифікатор зберігає SHA-256 автентифікованого бітового рядка (типи слів 1 – 5, як їх охоплює ADKD 0) і найновішого такого рядка, який надсилає супутник, і вони мають бути рівними. Скопійований IODnav над іншими словами або змінені біти слова типу 5 (які не несуть IODnav) читаються як Unavailable, доки нові дані не автентифікуються. Підкадр, що несе слова ефемерид, але не повний набір типів слів 1 – 5 під одним IODnav, так само забирає статус (кожен справжній підкадр E1-B несе всі п'ять); підкадр без жодних слів ефемерид нічого не каже. Теги іншого супутника (перехресна автентифікація) враховуються для супутника, чиї дані вони охоплюють.
  • Failed, коли перевірка даних супутника не пройшла в межах пам'яті відмов (600 с за замовчуванням від часу верифікатора), навіть якщо пізніші дані перевіряються. Розбіжність зараховується супутнику, чиї дані охоплює тег, і супутнику, що передав тег, бо винним може бути будь-який; розбіжність MACSEQ зараховується супутнику, що передає.
  • Unavailable в інших випадках, і для кожного супутника після перевіреного попереджувального повідомлення, зі статусом NMA «не використовувати» або зарезервованим статусом, і доки не перевірено перший ключ.

Загальне значення — Failed, якщо будь-який супутник не пройшов, Authenticated, якщо принаймні один автентифікований і жоден не відмовив, інакше Unavailable. $PKSOS,<A|F|N>[,<sat>:<A|F|N>...] — відповідне речення; kshana::osnma::pksos_sentence його будує.

Час#

Ланцюг ключів показує, що ключ належить заданому підкадру, а не що підкадр є поточним. Тому верифікатор ніколи не бере «зараз» з неперевіреної сторінки. Його час — пізніший із еталонного часу, заданого через set_reference_time (--reference-time), і підкадру найновішого перевіреного ключа TESLA (ключ не може бути відомий до свого слота, тож він доводить, що час не раніший). Пам'ять відмов, вікно чинності автентифікації та вилучення старих даних працюють за цим часом. Підкадр зі штампом більш ніж на три підкадри попереду найновішого перевіреного ключа відкладається, якщо його власний ключ не доводить його час; ключові та попереджувальні повідомлення в ньому все одно обробляються, бо несуть власний доказ (підпис або корінь Меркла).

Годинник стоїть, коли OSNMA зупиняється, бо рухають його лише ключі. Викликач у реальному часі має викликати set_reference_time із часом хоста кожен підкадр; автентифікація тоді спливає сама, а poll_clock (теж запускається з кожним підкадром) повертає подію KeyStall, коли жоден ключ не перевірявся довше за вікно автентифікації.

Чого це не дає — це свіжості. Без еталонного часу з джерела, яке зловмисник не може зсунути, повтор старих справжніх даних під старими штампами автентифікується, а штампи сторінок такі ж надійні, як їхнє джерело: CLI каже про це (freshness: NOT enforced), щойно еталонний час не задано. З еталонним часом допуск менший за один підкадр (за замовчуванням 29 с; більші значення відхиляються). Еталонний час — це один момент: підкадри, дальші від нього за допуск, відкладаються та враховуються, тож він підходить для живих чи щойно записаних даних, а не для довгого запису. Для запису не задавайте еталонний час і читайте результат як «справжнє, не обов'язково свіже». Формальну вимогу наведено в Керівних настановах для приймачів.

Штампи сторінок потоку u-blox походять із самих неавтентифікованих даних (див. Вхід), тож вони теж не забезпечують захисту від застарілості.

Ланцюги, ключі та попередження#

Перевірені ланцюги зберігаються за ідентифікатором ланцюга (CID); теги перевіряються ланцюгом, який називає заголовок NMA, а заголовок, що називає неперевірений ланцюг, залишає теги підкадру неперевіреними (chain_mismatch). Другий KROOT чинного ланцюга додає якір; KROOT іншого ланцюга зберігається поруч, тож повторне оголошення старого ланцюга після оновлення не скасовує нового.

Заголовок NMA не автентифікований, тож те, що він оголошує, враховується лише після підтвердження: коли більш ніж один супутник надсилає той самий заголовок у підкадрі або коли його несе підписане повідомлення перевіреного KROOT (заголовок є частиною цього повідомлення). Ці два випадки не рівні. Згода більш ніж одного супутника захищає від аномалії одного супутника, а не від спуфера: один спуфер може підробити два ідентифікатори супутників. Що це дає йому — відмова в обслуговуванні, і не більше, бо підтверджене «не використовувати» очищає автентифіковані дані кожного супутника: його зняття, підроблене чи справжнє, нічого не відновлює, доки нові теги не перевіряться під справжніми робочими підкадрами. (До цього очищення підроблене зняття могло повернути, на строк до вікна автентифікації, дані, що вже були автентифіковані.) Справжнє підтвердження — це заголовок, підписаний KROOT, який також знову знімає «не використовувати», коли несе робочий статус. Заголовок одного супутника не змінює нічого, окрім перевірки тегів власного підкадру. KROOT, чий час застосовності не пізніший за час ланцюга, що зберігається для того самого ідентифікатора (повтор старішого), відхиляється (stale); KROOT того самого ланцюга додає якір.

Статус і значення CPKS підтвердженого заголовка керують відкликанням. Зі статусом NMA «не використовувати» CPKS «ланцюг відкликано» відкидає ланцюг, названий заголовком, і відтоді відхиляє його KROOT; CPKS «відкритий ключ відкликано» відкидає відкритий ключ, що підписав цей ланцюг, і кожен ланцюг, підписаний ним. Якщо замінний ланцюг для цього ідентифікатора було прийнято до підтвердження заголовка, як би давно, відкликаний ключ — це ключ попереднього ланцюга, а не нового; ця пам'ять зберігається, доки відкликання не виконано або не підтверджено заголовок іншої процедури, а заголовок відкликання, що повторюється кожен підкадр, виконується один раз. Ті самі значення CPKS зі статусом «робочий» позначають перехід на заміну й нічого не відкликають. Сам заголовок не автентифікований, тож підроблене відкликання може лише забрати автентифікацію, і воно остаточне, доки верифікатор не буде перезапущено. Ця остаточність поширюється і на чинний ключ: підроблене відкликання відкритого ключа скидає пам'ять про замінений ключ і відкликає ключ, що використовується, і скасувати це може лише перезапуск.

DSM-PKR з NPKT 4 є попереджувальним повідомленням; воно перевіряється через дерево Меркла, як ключ, а його випадкове поле NPK є частиною листка. Перевірене попередження очищає всі ланцюги та відкриті ключі, відхиляє кожен наступний KROOT і відкритий ключ і робить кожен супутник Unavailable, як велять Керівні настанови для приймачів, доки верифікатор не буде перезапущено.

Поле заповнення DSM-KROOT — це геш підписаного повідомлення та підпису. Воно перевіряється перед підписом, а також каже, з яким заголовком NMA було побудовано підписане повідомлення, коли заголовок змінився під час складання повідомлення.

Що не перевіряється або не випробовується#

  • Свіжість. Див. Час вище: потрібен еталонний час ззовні.
  • Оновлення та відкликання. Ланцюги й ключі відстежуються так, як їх випробовують потоки опублікованих векторів (оновлення, кінець ланцюга, відкликання ланцюга та ключа, новий відкритий ключ, нове дерево Меркла, попередження), а не кожен випадок, який дозволяє ICD. Відкликання, оголошене неавтентифікованим заголовком, береться на слово й остаточне для сесії. Нове дерево Меркла підхоплюється лише через корінь Меркла, який отримує верифікатор.
  • Геш дерева Меркла. Повідомлення DSM-PKR перевіряються деревом SHA-256. Дерево SHA3-256, яке ICD дозволяє в майбутньому, не підтримується. Хеш-функція ланцюга може бути SHA-256 або SHA3-256.
  • Списки стану ключів. Відкликання відстежується через заголовок NMA та повідомлення в потоці; списки відкликання сертифікатів не читаються.
  • Охоплення автентифікованих даних. ADKD 4 із COP 1, надісланий у непарному підкадрі, не може автентифікуватися (тип слова 10 може надсилатися на один чи два підкадри раніше); це коштує лише доступності, ніколи правильності.
  • Операція за сталий час. Не забезпечується й не потрібна: верифікатор не тримає секретів (лише відкриті ключі, опубліковані ключі ланцюга та отримані дані).
  • Якість сигналу та даних. Сторінки перевіряються за CRC, а сторінки попереджень відкидаються, але про сигнал, яким вони прийшли, нічого не відомо. Відновлення Ріда–Соломона слів I/NAV 1 – 4 не використовується: дані мають прийматися безпосередньо.
  • Не послуга цілісності позиції. Автентифікація каже, що дані прийшли із системи. Вона нічого не каже про сигнал, яким вони прийшли, чи про якість визначення.

Вхідні дані#

  • Простий формат сторінок. Одна пара сторінок на рядок: <svid> <gst_seconds> <60 hex digits>, коментарі # дозволені. gst_seconds — це GST у секундах (week * 604800 + time of week) на початку сторінки; шістнадцяткове значення — це 240 бітів парної та непарної половин (разом із хвостами), старший біт першим.
  • CSV тестових векторів. Розкладка опублікованих векторів (SVID,NumNavBits,NavBitsHEX). Час початку береться з --start-gst або з датованої назви файлу.
  • u-blox UBX-RXM-SFRBX. Необроблений байтовий потік UBX (--format ubx, виявляється автоматично). Повідомлення Galileo E1-B I/NAV відновлюються в пари сторінок (src/osnma/ubx.rs); інші системи, E5b, сторінки попереджень і кадри з хибною контрольною сумою ігноруються. SFRBX не несе часу, тож кожна сторінка штампується за часом усередині власних даних (типи слів 5 і 0) і приймається, лише якщо послідовні сторінки з часом узгоджуються з кількістю сторінок, отриманих між ними; сторінки, які не вдається розмістити, відкидаються, а не вгадуються. Цей час походить із самих даних і не дає захисту від застарілості (див. Час вище). Ідентифікатор сигналу 0 (E1-C) не несе даних, тож приймати його поряд з E1-B нешкідливо. Випадкова пара синхронізації з абсурдною довжиною не затримує читач. Код кадрування — третя копія кадрування UBX у дереві (src/realdata/ubx.rs, вхід receiver-trust); його тримають окремо, щоб поведінка receiver-trust не змінилася, і ці три могли б згодом ділити один читач. Розкладку слів повідомлення SFRBX взято з публічних описів і перевірено лише на синтетичних кадрах, а не на живому приймачі.

Командний рядок#

kshana osnma verify <input> [--format pages|vector-csv|ubx] [--start-gst SECONDS]
    [--merkle-root HEX] [--public-key ID:TYPE:HEX]
    [--reference-time SECONDS [--max-time-error SECONDS]] [--epochs] [--json]

Текстовий вивід дає статус для кожного супутника та, з --epochs, для кожного тега й епохи; --json дає те саме зі списком тегів. Статус виходу 3 означає, що перевірка даних якогось супутника не пройшла, 2 — помилку використання чи входу. Консультативна примітка вище друкується першою на кожному шляху, зокрема для помилок і використання.

З Python і WebAssembly#

kshana.osnma_verify(data, format="", start_gst=None, merkle_root_hex="", public_keys=None, reference_time=None, max_time_error=None) (Python) і osnma_verify(input_base64, format, start_gst, merkle_root_hex, public_keys, reference_time, max_time_error) (WebAssembly) запускають той самий верифікатор на байтах у пам'яті та повертають JSON, який друкує kshana osnma verify --json, разом із консультативною приміткою. Сервер MCP його не містить: вхід — довгий необроблений потік приймача, який краще обслуговують командний рядок і Python, а інструмент агента додав би велику поверхню входу без жодної користі. Застосовуються та сама консультативна примітка й ті самі обмеження; статус не є послугою цілісності навігації.

Тести та тестові дані#

Тестові дані синтетичні та згенеровані власним кодом і тестами Kshana. Жодні вектори ICD чи Настанов, робочі приклади чи ключовий матеріал не зберігаються в цьому сховищі. Типові тести (tests/osnma_synthetic.rs і модульні тести) будують ланцюг, сторінки й теги з рівнянь і перевіряють узгодженість та те, що навмисне пошкодження виявляється: змінений навігаційний біт, змінений біт ключа, повторені теги, хибні часові штампи, час поза еталоном, відсутні дані та атаки, які виявив огляд (підроблений підкадр далекого майбутнього, який не повинен стирати відмову, автентифікація, що має спливати та слідувати IODnav, попередження, статус NMA «не використовувати», фіктивні теги, розбіжність MACSEQ, суперечливі ключі, відкликання й оновлення ланцюга, хибне заповнення чи підпис), з CMAC-AES, ланцюгом SHA3-256 і підписом P-521, проведеними через верифікатор. Оскільки ці дані походять із нашого власного читання ICD, вони показують самоузгодженість, а не відповідність.

Примітиви перевіряються за опублікованими тестами з відомою відповіддю, жоден не взято з ICD: RFC 4231 (HMAC-SHA-256), RFC 4493 (CMAC-AES-128), FIPS 197 (AES), FIPS 202 (SHA3-256) і RFC 6979 (ECDSA P-256). Підписи P-521 перевіряються на кодування та вибір хеша тимчасовим ключем, створеним у тесті; арифметика кривої належить бібліотеці.

Відповідність перевіряє tests/osnma_official_vectors.rs, який вмикається за бажанням: він читає копію офіційного архіву тестових векторів, яку ви завантажуєте самі, з каталогу, названого KSHANA_OSNMA_VECTORS, і нічого не робить, коли змінну не задано. Він нічого не зберігає й не поширює, а типові запуски тестів не використовують мережі. Він дає верифікатору лише корінь Меркла та відкриті ключі одного дерева, як мав би приймач, тож ланцюги встановлюються з підписаного DSM-KROOT у потоці й проходить весь шлях: Меркл, підпис, ланцюг ключів, MACSEQ і теги. Для кожного набору векторів він стверджує нижню межу автентифікованих тегів, що жоден не відмовив, які ланцюги та ключі оголошує потік, автентифіковані теги ADKD 0, 4 і 12, що автентифікація відновлюється після кінця ланцюга, відкликання ланцюга, відкликання ключа та нового відкритого ключа, що попереджувальне повідомлення перевіряється й не залишає нічого автентифікованого, і що кожен вектор використовує лише HMAC-SHA-256, ланцюг SHA-256, 128-бітні ключі, 40-бітні теги та записи таблиці пошуку 33 і 34. Інші вибори алгоритмів і параметрів ICD тому охоплені лише тестами з відомою відповіддю та синтетичними тестами вище.

Залежності#

Крейти RustCrypto, чистий Rust, MIT OR Apache-2.0, зібрані без типових можливостей: hmac, cmac, aes, sha3, p256 і p521 (можливість ecdsa, що використовується лише для перевірки), поряд з sha2, що вже є в дереві. Вони збираються для wasm32-unknown-unknown і проходять cargo deny.