Packages

An elixir library for MAVLink, an application that enables communication with other systems using the MAVLink protocol over serial, UDP and TCP connections, and utility modules for performing common MAVLink commands and tasks with one or more remote vehicles.

Current section

Files

Jump to
xmavlink MAVLINK2_SIGNING.md
Raw

MAVLINK2_SIGNING.md

# MAVLink 2 Signing Guide
Primary references:
- MAVLink message signing: https://mavlink.io/en/guide/message_signing.html
- MAVLink packet serialization: https://mavlink.io/en/guide/serialization.html
## Overview
XMAVLink parses the MAVLink 2 signing incompatibility flag (`0x01`) as a known
frame-shape feature and extracts the 13-byte signing trailer into
`XMAVLink.Frame.Signature`.
`XMAVLink.Frame.sign_frame/4` can sign an already packed MAVLink 2 frame when
given a 32-byte key, link id, and timestamp. Router forwarding uses it through
`XMAVLink.Signing.sign_outbound/2` when a signing-enabled connection sends an
unsigned MAVLink 2 frame.
`XMAVLink.Frame.validate_signature/2` verifies the 48-bit signature for a
parsed signed frame. `XMAVLink.Signing.validate_inbound/2` adds the policy
state needed for replay protection by tracking the last accepted timestamp per
`{source_system, source_component, link_id}` stream and rejecting first-seen
streams more than 6,000,000 ticks behind the local signing timestamp.
Routers accept a `:signing` configuration with `:secret_key`, `:link_id`,
`:timestamp`, optional `:accept_unsigned`, optional `:accept_mavlink1`, and
optional timestamp persistence callbacks. Receive paths seed each connection
with that policy. Configured signed MAVLink 2 frames are verified before dialect
unpacking, delivered to subscribers, forwarded through the normal routing logic,
and recorded for replay protection. Unsigned MAVLink 2 inbound frames are
rejected by default while signing is enabled unless `accept_unsigned: true` is
set. MAVLink 1 frames remain accepted under a signing policy unless
`accept_mavlink1: false` is configured. When signing is not configured, signed
MAVLink 2 frames still return `:signed_frame_unsupported`.
Outbound routing signs unsigned MAVLink 2 frames on signing-enabled
connections, updates that connection's local timestamp after each signed send,
and leaves MAVLink 1 frames unsigned. Already signed MAVLink 2 frames are
forwarded with their existing signature rather than being re-signed. If a
timestamp save callback is configured and the local timestamp advances, the
callback must succeed before a signed inbound frame is accepted or an outbound
signed frame is emitted.
Unknown incompatible flags are still rejected. If a frame has both the signing
flag and unsupported incompatible flags, XMAVLink consumes the known 13-byte
signature trailer when present so stream transports keep frame boundaries, but
the packet is not accepted.
`SETUP_SIGNING` frames carry key material. Inbound `SETUP_SIGNING` frames are
delivered to local subscribers but are not forwarded from one MAVLink connection
to another by generic routing. Locally originated `SETUP_SIGNING` frames are
still routed normally so applications can build an intentional provisioning
flow, but XMAVLink does not automate key provisioning or key rotation.
## Signature Frame Shape
The MAVLink 2 signed trailer is 13 bytes:
- `link_id`: 8-bit link identifier.
- `timestamp`: little-endian 48-bit timestamp in 10 microsecond units since
2015-01-01 00:00:00 GMT.
- `signature`: 48-bit signature value.
The signature is defined as the first 48 bits of SHA-256 over the 32-byte shared
secret key followed by the wire header including the magic byte, payload, CRC,
link id, and timestamp.
## Public Policy Shape
Signing is currently configured per router and copied into each connection:
- `signing: nil` or omitted: current unsigned behavior, but signed frames remain
rejected until an explicit acceptance policy is configured.
- `signing: [secret_key: <<_::256>>, link_id: 0..255, timestamp: non_neg_integer]`:
validate inbound signed MAVLink 2 frames, track inbound replay timestamps, and
sign unsigned outbound MAVLink 2 frames on each connection.
- `accept_unsigned: false | true`: explicit policy for unsigned frames when
signing is enabled. The policy helper defaults to reject.
- `accept_mavlink1: true | false`: explicit policy for MAVLink 1 frames when
signing is enabled. The policy helper defaults to accept for mixed-link
compatibility. Set false for signed-only deployments that should reject
MAVLink 1 inbound and outbound traffic on signing-enabled connections.
- `timestamp_load: fun | {module, function, args}`: optional zero-arity callback
that returns a previously saved timestamp, `{:ok, timestamp}`, or `nil` when
no timestamp has been saved yet. Loaded timestamps are combined with the
configured or current timestamp by taking the maximum value. `:error`,
`{:error, reason}`, invalid timestamps, or callback failures reject the
signing configuration.
- `timestamp_save: fun | {module, function, args}`: optional one-arity callback
that receives each advanced local timestamp and returns `:ok` or
`{:ok, result}`. MFA callbacks receive the timestamp appended to `args`.
Save failures return `:timestamp_save_failed` to the caller and prevent that
state-advancing frame from being accepted or emitted.
## Operational Notes
Applications are responsible for storing shared keys and persisted timestamps
securely. Timestamp persistence callbacks should write to durable storage before
returning `:ok`; otherwise XMAVLink will treat the save as failed and reject
the state-advancing frame.