1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*!
# 📖 2.2. Message Signing
<em>[← Dialect Constraints](crate::docs::b1__dialect_constraints) | [Compatibility →](crate::docs::b3__compat_checks)</em>
Second version of MAVLink protocol adds a capability to
[authenticate](https://mavlink.io/en/guide/message_signing.html) sender by adding a
cryptographic [`signature`] to a frame. When frames are signed, they have a special
[`MAVLINK_IFLAG_SIGNED`] set in their incompatibility flags ([`incompat_flags`]). A receiver can
validate the [`signature`] and either reject unauthorized frame or process it based on the
[`link_id`](Signature::link_id) of the signature.
## Contents
1. [Basics](#basics)
1. [Signing Strategies](#signing-strategies)
1. [Multiple Links](#multiple-links)
1. [Excluding Messages](#excluding-messages)
1. [Unknown Links](#unknown-links)
## Basics
In Maviola we provide a special frame processor called [`FrameSigner`] responsible to signing and
validating frames, when added to a [`Node`]:
```rust,no_run
use maviola::prelude::*;
use maviola::sync::prelude::*;
let node = Node::sync::<V2>()
.signer(FrameSigner::new(11, "secure key"))
# .connection(TcpClient::new("127.0.0.1:5600").unwrap())
/* other node settings */
.build().unwrap();
```
This will set a [`SecretKey`] for link with `id=11`. This will validate all signed messages and
sign unsigned messages.
## Signing Strategies
Sometimes we need a more nuanced approach to signing. The frame signer can be built with distinct
strategies for [`incoming`] and [`outgoing`] frames. The strategy in each case is defined by
[`SignStrategy`] enum. For example:
```rust,no_run
# use maviola::prelude::*;
# use maviola::sync::prelude::*;
#
let node = Node::sync::<V2>()
.signer(FrameSigner::builder()
.link_id(11)
.key("secret key")
.incoming(SignStrategy::Strict)
.outgoing(SignStrategy::Strip)
)
# .connection(TcpClient::new("127.0.0.1:5600").unwrap())
/* other node settings */
.build().unwrap();
```
This will apply a strict validation for incoming messages and will strip signatures from outgoing
messages.
## Multiple Links
Since `MAVLink 2` protocol supports multiple links, Maviola provides a way to specify additional
links and secret keys. These links with the corresponding keys will be used only for validation.
Frames will always be signed by the main [`key`] and [`link_id`].
```rust,no_run
# use maviola::prelude::*;
# use maviola::sync::prelude::*;
#
let node = Node::sync::<V2>()
.signer(FrameSigner::builder()
.link_id(11)
.key("secret key")
.add_link(17, "another key")
.add_link(217, "yet another key")
)
# .connection(TcpClient::new("127.0.0.1:5600").unwrap())
/* other node settings */
.build().unwrap();
```
## Excluding Messages
You can exclude certain message `ID`s from signature processing by using `exclude` method of a
frame signer builder.
```rust,no_run
# use maviola::prelude::*;
# use maviola::sync::prelude::*;
#
let node = Node::sync::<V2>()
.signer(FrameSigner::builder()
.link_id(11)
.key("secret key")
.exclude(&[0, 23, 240])
)
# .connection(TcpClient::new("127.0.0.1:5600").unwrap())
/* other node settings */
.build().unwrap();
```
## Unknown Links
All mentioned rules are strict when applied to frames with unknown link `ID`s. These messages will
be considered always invalid. There is a way to bypass these rules by setting [`unknown_links`]
signing strategy:
```rust,no_run
# use maviola::prelude::*;
# use maviola::sync::prelude::*;
#
let node = Node::sync::<V2>()
.signer(FrameSigner::builder()
.link_id(11)
.key("secret key")
.unknown_links(SignStrategy::ReSign)
)
# .connection(TcpClient::new("127.0.0.1:5600").unwrap())
/* other node settings */
.build().unwrap();
```
This will use the main [`key`] to validate frames from unknown links and re-sign them with the main
[`link_id`].
**`⍚`** Unfortunately, this part of API is not stable enough and therefore available only, when
`unstable` Cargo feature is enabled. There is a dedicated
[issue](https://gitlab.com/mavka/libs/maviola/-/issues/3) you can track.
<em>[← Dialect Constraints](crate::docs::b1__dialect_constraints) | [Compatibility →](crate::docs::b3__compat_checks)</em>
[`signature`]: Frame::signature
[`incompat_flags`]: Frame::incompat_flags
[`MAVLINK_IFLAG_SIGNED`]: IncompatFlags::MAVLINK_IFLAG_SIGNED
[`incoming`]: FrameSigner::incoming
[`outgoing`]: FrameSigner::outgoing
[`link_id`]: FrameSigner::link_id
[`key`]: FrameSigner::key
[`unknown_links`]: FrameSigner::unknown_links
*/
use crate*;
use crate*;