Maskinöversättning, inte granskad av en modersmålstalare. Engelska är referensen.

Mottagarförtroende och sjöfartRedigera på GitHubKälla: docs/OSNMA.md

Galileo OSNMA-verifierare på mottagarsidan

En verifierare på mottagarsidan för Galileo Open Service Navigation Message Authentication (OSNMA), i ren Rust. Den läser I/NAV-sidor och redovisar, per satellit och per epok, om navigeringsdata är kryptografiskt autentiserade, och varför en kontroll misslyckades.

Rådgivande. Detta är analys- och övervakningsutdata och inte typgodkänd navigationsutrustning. Autentiseringsstatusen som redovisas här är inte en tjänst för navigeringsintegritet och får inte vara den enda grunden för något navigerings- eller säkerhetsbeslut.

MEDDELANDE: immateriella rättigheter i Galileo OSNMA-gränssnittet#

Kshana beviljar inga rättigheter under Europeiska unionens immateriella rättigheter i Galileo OSNMA Signal-in-Space Interface Control Document ("ICD IPRs"). ICD:n bär sitt eget tillstånd (dess bilaga E), som är icke-exklusivt och royaltyfritt och har egna villkor, omfattning och begränsningar. Den som använder, bygger eller distribuerar programvara baserad på den här modulen förlitar sig direkt på det tillståndet och måste själv läsa och godta dess villkor. Kshanas licens (endast AGPL-3.0, eller den kommersiella licensen) omfattar bara Kshanas egen kod.

Den här modulen implementerar de algoritmer som dokumenten nedan beskriver. ICD-texten återges inte; numeriska värden (fältlayouter, uppräkningar, MAC-uppslagstabellen) uttrycks på nytt i Kshanas egen notation, med källan angiven i koden. ICD:n och Receiver Guidelines är © Europeiska unionen; källan erkänns här. Kshana är inte utvecklad av, använd av, godkänd av eller stödd av Europeiska unionen, Europeiska kommissionen, EUSPA eller något annat organ.

Referensdokument#

Utgivna av European GNSS Service Centre.

Dokument Version Datum
Galileo OSNMA Signal-in-Space ICD ("SIS ICD") Utgåva 1,1 oktober 2023
Galileo OSNMA Receiver Guidelines Utgåva 1,3 januari 2024

Avsnitts- och tabellnummer som anges i koden och här avser de versionerna.

Vad som verifieras#

Förtroendekedjan, från roten ner till data:

  1. Publik nyckel (ICD 3.2.2, 6,2). Ett DSM-PKR sätts ihop på nytt av sina block och dess Merkle-sökväg följs till en betrodd Merkle-rot (SHA-256).
  2. KROOT (ICD 3.2.3, 6,3). Ett DSM-KROOT sätts ihop på nytt; dess ECDSA-signatur (P-256/SHA-256 eller P-521/SHA-512) kontrolleras mot den publika nyckel den namnger, över NMA-huvudet och kedjeparametrarna.
  3. TESLA-nycklar (ICD 5,5, 6,4). Varje nyckel i ett MACK-meddelande följs tillbaka till KROOT eller till en tidigare verifierad nyckel, med kedjans hashfunktion.
  4. MACSEQ (ICD 4.1.2, 6,6). De flexibla Tag-Info-fälten kontrolleras mot MACSEQ med den nyckel som öppnar det MACK:et.
  5. Taggar (ICD 4,2, 6,7). Varje tagg räknas om (HMAC-SHA-256 eller CMAC-AES, avkortad till kedjans taggängd) över satellitidentiteterna, delramens tid, taggens position, NMA-statusen och den navigeringsdata den täcker, och jämförs. ADKD 0 (efemerid, klocka och status), ADKD 4 (tidsparametrar) och ADKD 12 (långsam MAC, nyckeln publiceras tio delramar senare) hanteras, med korsautentisering av satelliter som inte själva bär OSNMA, och dummytaggar (COP 0).

En tagg som anger ett reserverat värde, eller vars ADKD inte stämmer med platsen i MAC-uppslagstabellen, läggs åt sidan (mottagarriktlinjerna säger att den ska kasseras) och rapporteras som discarded, inte som ett fel.

Sidor kontrolleras mot sin CRC (Galileos CRC-24Q) före allt annat; en sida som misslyckas slängs och rapporteras (bad_crc).

Statusvärden#

Per tagg: authenticated, failed med en orsak (tag_mismatch, macseq_mismatch, key_chain_mismatch, key_conflict), pending med en orsak (no_chain, awaiting_key, no_nav_data, unknown_maclt, unsupported_function, service_not_usable, chain_mismatch), eller discarded. En dummytagg (COP 0) visas som authenticated på taggnivå, eftersom den bevisar nyckeln, men den täcker ingen navigeringsdata och räknas aldrig för en satellit.

Per satellit, i den form som övervakaren för mottagarförtroende använder:

  • Authenticated bara så länge de senaste verifierade efemerid- och klockdata (ADKD 0 eller
    1. för den satelliten är färska (inom 600 s från verifierarens tid som standard) och fortfarande är de data som används. Kontrollen gäller data, inte IODnav: verifieraren behåller SHA-256 för den autentiserade bitsträngen (ordtyp 1 till 5 såsom ADKD 0 täcker dem) och för den senaste sådana strängen som satelliten skickar, och de måste vara lika. En kopierad IODnav över andra ord, eller ändrade bitar i ordtyp 5 (som inte bär någon IODnav), läses som Unavailable tills de nya data autentiseras. En delram som bär efemeridord men ingen komplett uppsättning ordtyp 1 till 5 under en IODnav tar bort statusen på samma sätt (varje äkta E1-B-delram bär alla fem); en utan några efemeridord alls säger ingenting. Taggar från en annan satellit (korsautentisering) räknas för den satellit vars data de täcker.
  • Failed när en kontroll av satellitens data misslyckades inom felminnet (600 s som standard av verifierarens tid), även om senare data verifieras. En avvikelse läggs på den satellit vars data taggen täcker och på den satellit som sände taggen, eftersom någondera kan ha fel; en MACSEQ-avvikelse läggs på den sändande satelliten.
  • Unavailable annars, och för varje satellit efter ett verifierat varningsmeddelande, med NMA-status "don't use" eller en reserverad status, och tills den första nyckeln har verifierats.

Det samlade värdet är Failed om någon satellit misslyckades, Authenticated om minst en är autentiserad och ingen misslyckades, annars Unavailable. $PKSOS,<A|F|N>[,<sat>:<A|F|N>...] är motsvarande mening; kshana::osnma::pksos_sentence bygger den.

Tid#

Nyckelkedjan visar att en nyckel hör till en viss delram, inte att delramen är den aktuella. Verifieraren hämtar därför aldrig "nu" från en overifierad sida. Dess tid är den senare av referenstiden som anges med set_reference_time (--reference-time) och delramen för den senaste TESLA-nyckel som verifierats (en nyckel kan inte vara känd före sin lucka, så den bevisar att tiden inte är tidigare). Felminne, giltighetsfönstret för en autentisering och avlägsnandet av gamla data styrs av den tiden. En delram stämplad mer än tre delramar efter den senaste verifierade nyckeln läggs åt sidan om inte dess egen nyckel bevisar dess tid; nyckel- och varningsmeddelanden i den behandlas ändå, eftersom de bär sitt eget bevis (en signatur eller Merkle-roten).

Klockan står still när OSNMA slutar, eftersom bara nycklar för den framåt. En live-anropare måste anropa set_reference_time med värdtid varje delram; autentiseringen löper då ut av sig själv, och poll_clock (som också körs för varje delram) returnerar en KeyStall-händelse när ingen nyckel har verifierats under längre tid än autentiseringsfönstret.

Det detta inte ger är färskhet. Utan en referenstid från en källa som en angripare inte kan flytta autentiseras en replay av gamla äkta data under gamla stämplar, och sidstämplarna är bara så bra som sin källa: kommandoradsverktyget säger det (freshness: NOT enforced) så snart ingen referenstid anges. Med en referenstid är toleransen under en delram (standard 29 s; större värden avvisas). En referenstid är ett enda ögonblick: delramar längre från den än toleransen läggs åt sidan och räknas, så den passar live- eller nyss inspelade data, inte en lång inspelning. För en inspelning, utelämna referenstiden och läs resultatet som "äkta, inte nödvändigtvis färskt". Mottagarriktlinjerna ger det formella kravet.

Sidstämplarna i en u-blox-ström kommer från de oautentiserade data själva (se Indata), så de ger inte heller något färskhetsskydd.

Kedjor, nycklar och varningar#

Verifierade kedjor lagras per kedje-id (CID); taggar kontrolleras med den kedja som NMA-huvudet anger, och ett huvud som anger en kedja som inte verifierats lämnar delramens taggar okontrollerade (chain_mismatch). En andra KROOT för en gällande kedja lägger till ett ankare; en KROOT för en annan kedja behålls vid sidan, så att ett nytt tillkännagivande av den gamla kedjan efter en förnyelse inte upphäver den nya.

NMA-huvudet är inte autentiserat, så det det tillkännager räknas bara när det bekräftas: när fler än en satellit skickar samma huvud i en delram, eller när det signerade meddelandet i en verifierad KROOT bär det (huvudet är en del av det meddelandet). De två är inte likvärdiga. Samstämmighet mellan fler än en satellit skyddar mot en avvikelse hos en enskild satellit, inte mot en spoofer: en spoofer kan förfalska två satellit-id. Vad det ger den är denial of service, och inget mer eftersom ett bekräftat "don't use" rensar varje satellits autentiserade data: att häva det, förfalskat eller äkta, återställer ingenting förrän nya taggar verifieras under äkta operativa delramar. (Före den rensningen kunde en förfalskad hävning ge tillbaka, i upp till autentiseringsfönstret, data som redan hade autentiserats.) Den verkliga bekräftelsen är det KROOT-signerade huvudet, som också häver ett "don't use" igen när det bär en operativ status. En enskild satellits huvud ändrar ingenting utom kontrollen av taggarna i dess egen delram. En KROOT vars tillämpbarhetstid inte är senare än den för kedjan som innehas för samma id (en replay av en äldre) avvisas (stale); en KROOT för samma kedja lägger till ett ankare.

Det bekräftade huvudets status och CPKS-värde styr återkallelse. Med NMA-status "don't use" tar CPKS "chain revoked" bort den kedja som huvudet anger och avvisar dess KROOT från och med då; CPKS "public key revoked" tar bort den publika nyckel som signerade den kedjan, och varje kedja signerad med den. Om ersättningskedjan för det id:t antogs innan huvudet bekräftades, hur långt före som helst, är den återkallade nyckeln den föregående kedjans, inte den nya; det minnet behålls tills återkallelsen genomförs eller en annan procedurs huvud bekräftas, och ett återkallelsehuvud som upprepas varje delram genomförs en gång. Samma CPKS-värden med status operational markerar övergången till ersättningen och återkallar ingenting. Huvudet är inte självt autentiserat, så en förfalskad återkallelse kan bara ta bort autentisering, och den är slutgiltig tills verifieraren startas om. Den slutgiltigheten gäller även den levande nyckeln: en förfalskad återkallelse av publik nyckel nollställer minnet av den ersatta nyckeln och återkallar nyckeln som används, och bara en omstart ångrar det.

Ett DSM-PKR med NPKT 4 är varningsmeddelandet; det verifieras genom Merkle-trädet som en nyckel, där dess slumpmässiga NPK-fält ingår i bladet. Ett verifierat varningsmeddelande rensar alla kedjor och publika nycklar, avvisar varje senare KROOT och publik nyckel, och gör varje satellit Unavailable, som mottagarriktlinjerna föreskriver, tills verifieraren startas om.

Utfyllnadsfältet i ett DSM-KROOT är en hash av det signerade meddelandet och signaturen. Det kontrolleras före signaturen, och det anger också vilket NMA-huvud det signerade meddelandet byggdes med när huvudet ändrades medan meddelandet sattes ihop.

Vad som inte verifieras, eller inte prövas#

  • Färskhet. Se Tid ovan: den behöver en referenstid utifrån.
  • Förnyelse och återkallelse. Kedjor och nycklar följs så som strömmarna i de publicerade vektorerna prövar dem (förnyelse, kedjeslut, kedje- och nyckelåterkallelse, ny publik nyckel, nytt Merkle-träd, varning), inte varje fall som ICD tillåter. En återkallelse som tillkännages av det oautentiserade huvudet tas på orden och är slutgiltig för sessionen. Ett nytt Merkle-träd plockas upp bara genom den Merkle-rot som verifieraren får.
  • Merkle-trädets hash. DSM-PKR-meddelanden kontrolleras med ett SHA-256-träd. Ett SHA3-256-träd, som ICD tillåter i framtiden, stöds inte. Kedjans hashfunktion kan vara SHA-256 eller SHA3-256.
  • Nyckelstatuslistor. Återkallelse följs genom NMA-huvudet och meddelandena i strömmen; listor över återkallade certifikat läses inte.
  • Täckning av autentiserade data. ADKD 4 med COP 1 skickad i en udda delram kan inte autentisera (ordtyp 10 kan skickas en eller två delramar tidigare); detta kostar bara tillgänglighet, aldrig korrekthet.
  • Drift i konstant tid. Tillhandahålls inte och behövs inte: verifieraren håller inga hemligheter (bara publika nycklar, publicerade kedjenycklar och mottagna data).
  • Signal- och datakvalitet. Sidor CRC-kontrolleras och varningssidor slängs, men inget är känt om signalen de kom in på. Reed-Solomon-återvinning av I/NAV-orden 1 till 4 används inte: data måste tas emot direkt.
  • Inte en integritetstjänst för position. Autentisering säger att data kom från systemet. Den säger ingenting om signalen den kom in på eller positionsbestämningens kvalitet.

Indata#

  • Enkelt sidformat. Ett sidpar per rad: <svid> <gst_seconds> <60 hex digits>, #-kommentarer tillåtna. gst_seconds är GST i sekunder (week * 604800 + time of week) vid sidans början; hexvärdet är de 240 bitarna i den jämna och den udda hälften (svansar inkluderade), mest signifikanta biten först.
  • Testvektor-CSV. Layouten för de publicerade vektorerna (SVID,NumNavBits,NavBitsHEX). Starttiden kommer från --start-gst eller från ett daterat filnamn.
  • u-blox UBX-RXM-SFRBX. En rå UBX-bytesström (--format ubx, identifieras automatiskt). Galileo E1-B I/NAV-meddelanden byggs om till sidpar (src/osnma/ubx.rs); andra system, E5b, varningssidor och ramar med felaktig kontrollsumma ignoreras. SFRBX bär ingen tid, så varje sida stämplas utifrån tiden i dess egna data (ordtyp 5 och 0) och godtas bara om på varandra följande tidsbärande sidor stämmer med antalet sidor som mottagits mellan dem; sidor som inte kan placeras slängs, aldrig gissas. Den tiden kommer från själva data och ger inget färskhetsskydd (se Tid ovan). Signal-id 0 (E1-C) bär inga data, så att godta den vid sidan av E1-B är ofarligt. Ett löst synkpar med en orimlig längd håller inte tillbaka läsaren. Ramningskoden är en tredje kopia av UBX-ramningen i trädet (src/realdata/ubx.rs, inläsningen för mottagarförtroende); den hålls isär så att receiver-trust-beteendet är oförändrat, och de tre kunde dela en läsare senare. Ordlayouten i ett SFRBX-meddelande är hämtad från offentliga beskrivningar och kontrollerad bara på syntetiska ramar, inte på en levande mottagare.

Kommandorad#

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]

Textutdata ger status per satellit och, med --epochs, per tagg och epok; --json ger samma med taglistan. Avslutsstatus 3 betyder att en kontroll av någon satellits data misslyckades, 2 betyder ett användnings- eller indatafel. Det rådgivande uttalandet ovan skrivs ut först på varje väg, fel och användning inkluderade.

Från Python och WebAssembly#

kshana.osnma_verify(data, format="", start_gst=None, merkle_root_hex="", public_keys=None, reference_time=None, max_time_error=None) (Python) och osnma_verify(input_base64, format, start_gst, merkle_root_hex, public_keys, reference_time, max_time_error) (WebAssembly) kör samma verifierare på bytes i minnet och returnerar den JSON som kshana osnma verify --json skriver ut, rådgivande uttalande inkluderat. MCP-servern har den inte: indata är en lång rå mottagarström som bättre betjänas av kommandoraden och Python, och ett agentverktyg skulle lägga till en stor yta för indata utan någon nytta. Samma rådgivande uttalande och samma begränsningar gäller; statusen är inte en integritetstjänst för navigering.

Tester och testdata#

Testdata är syntetiska och genereras av Kshanas egen kod och tester. Inga ICD- eller riktlinjevektorer, genomgångna exempel eller nyckelmaterial lagras i det här repositoriet. Standardtesterna (tests/osnma_synthetic.rs och enhetstesterna) bygger en kedja, sidor och taggar utifrån ekvationerna och kontrollerar konsistens och att avsiktlig korruption fångas: en vänd navigeringsbit, en vänd nyckelbit, återspelade taggar, fel tidsstämplar, en tid utanför referensen, saknade data, och de attacker som granskningen hittade (en spoofad delram långt in i framtiden som inte får radera ett fel, autentisering som måste löpa ut och följa IODnav, en varning, NMA-status "don't use", dummytaggar, MACSEQ-avvikelse, motstridiga nycklar, kedjeåterkallelse och förnyelse, en felaktig utfyllnad eller signatur), med CMAC-AES, en SHA3-256-kedja och en P-521-signatur genom verifieraren. Eftersom de datan kommer från vår egen läsning av ICD visar den självkonsistens, inte överensstämmelse.

Primitiverna kontrolleras mot publicerade known-answer-tester, inga hämtade från ICD: RFC 4231 (HMAC-SHA-256), RFC 4493 (CMAC-AES-128), FIPS 197 (AES), FIPS 202 (SHA3-256) och RFC 6979 (ECDSA P-256). P-521-signaturer kontrolleras för kodning och hashval med en engångsnyckel som skapas i testet; kurvaritmetiken är bibliotekets.

Kontrollen mot de officiella vektorerna görs av tests/osnma_official_vectors.rs, som är opt-in: den läser en kopia av det officiella testvektorarkivet som du själv laddar ner, från katalogen som anges av KSHANA_OSNMA_VECTORS, och gör ingenting när variabeln inte är satt. Den lagrar och vidaredistribuerar ingenting, och standardtestkörningar använder inget nätverk. Den ger verifieraren bara en Merkle-rot och de publika nycklarna för ett träd, som en mottagare skulle ha, så kedjor upprättas från det signerade DSM-KROOT i strömmen och hela vägen körs: Merkle, signatur, nyckelkedja, MACSEQ och taggar. Den hävdar, per vektoruppsättning, en nedre gräns för de autentiserade taggarna, att ingen misslyckades, vilka kedjor och nycklar strömmen tillkännager, autentiserade taggar av ADKD 0, 4 och 12, att autentisering återupptas efter kedjeslut, kedjeåterkallelse, nyckelåterkallelse och ny publik nyckel, att varningsmeddelandet verifieras och inte lämnar något autentiserat, och att varje vektor bara använder HMAC-SHA-256, en SHA-256-kedja, 128-bitarsnycklar, 40-bitarstaggar och uppslagsposterna 33 och 34. Andra algoritm- och parameterval i ICD täcks därför bara av known-answer-testerna och de syntetiska testerna ovan.

Beroenden#

RustCrypto-crates, ren Rust, MIT OR Apache-2.0, byggda utan standardfunktioner: hmac, cmac, aes, sha3, p256 och p521 (funktionen ecdsa, används bara för verifiering), vid sidan av sha2 som redan finns i trädet. De byggs för wasm32-unknown-unknown och klarar cargo deny.