APM:Libraries
GCS_Signing.cpp
Go to the documentation of this file.
1 /*
2  Code for handling MAVLink2 signing
3 
4  This program is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "GCS.h"
19 
20 extern const AP_HAL::HAL& hal;
21 
22 // storage object
24 
25 // magic for versioning of the structure
26 #define SIGNING_KEY_MAGIC 0x3852fcd1
27 
28 // structure stored in FRAM
29 struct SigningKey {
30  uint32_t magic;
31  uint64_t timestamp;
32  uint8_t secret_key[32];
33 };
34 
35 // shared signing_streams structure
36 mavlink_signing_streams_t GCS_MAVLINK::signing_streams;
37 
38 // last time we saved the timestamp
40 
42 {
43  if (_signing_storage.size() < sizeof(key)) {
44  return false;
45  }
46  return _signing_storage.write_block(0, &key, sizeof(key));
47 }
48 
50 {
51  if (_signing_storage.size() < sizeof(key)) {
52  return false;
53  }
54  if (!_signing_storage.read_block(&key, 0, sizeof(key))) {
55  return false;
56  }
57  if (key.magic != SIGNING_KEY_MAGIC) {
58  return false;
59  }
60  return true;
61 }
62 
63 /*
64  handle a setup_signing message
65  */
66 void GCS_MAVLINK::handle_setup_signing(const mavlink_message_t *msg)
67 {
68  // decode
69  mavlink_setup_signing_t packet;
70  mavlink_msg_setup_signing_decode(msg, &packet);
71 
72  struct SigningKey key;
74  key.timestamp = packet.initial_timestamp;
75  memcpy(key.secret_key, packet.secret_key, 32);
76 
77  if (!signing_key_save(key)) {
78  hal.console->printf("Failed to save signing key");
79  return;
80  }
81 
82  // activate it immediately
83  load_signing_key();
84 }
85 
86 
87 /*
88  callback to accept unsigned (or incorrectly signed) packets
89  */
90 extern "C" {
91 
92 static const uint32_t accept_list[] = {
93  MAVLINK_MSG_ID_RADIO_STATUS,
94  MAVLINK_MSG_ID_RADIO
95 };
96 
97 static bool accept_unsigned_callback(const mavlink_status_t *status, uint32_t msgId)
98 {
99  if (status == mavlink_get_channel_status(MAVLINK_COMM_0)) {
100  // always accept channel 0, assumed to be secure channel. This
101  // is USB on PX4 boards
102  return true;
103  }
104  for (uint8_t i=0; i<ARRAY_SIZE(accept_list); i++) {
105  if (accept_list[i] == msgId) {
106  return true;
107  }
108  }
109  return false;
110 }
111 }
112 
113 /*
114  load signing key
115  */
117 {
118  struct SigningKey key;
119  if (!signing_key_load(key)) {
120  return;
121  }
122  mavlink_status_t *status = mavlink_get_channel_status(chan);
123  if (status == nullptr) {
124  hal.console->printf("Failed to load signing key - no status");
125  return;
126  }
127  memcpy(signing.secret_key, key.secret_key, 32);
128  signing.link_id = (uint8_t)chan;
129  // use a timestamp 1 minute past the last recorded
130  // timestamp. Combined with saving the key once every 30s this
131  // prevents a window for replay attacks
132  signing.timestamp = key.timestamp + 60UL * 100UL * 1000UL;
133  signing.flags = MAVLINK_SIGNING_FLAG_SIGN_OUTGOING;
134  signing.accept_unsigned_callback = accept_unsigned_callback;
135 
136  // if timestamp and key are all zero then we disable signing
137  bool all_zero = (key.timestamp == 0);
138  for (uint8_t i=0; i<sizeof(key.secret_key); i++) {
139  if (signing.secret_key[i] != 0) {
140  all_zero = false;
141  }
142  }
143 
144  // enable signing on all channels
145  for (uint8_t i=0; i<MAVLINK_COMM_NUM_BUFFERS; i++) {
146  mavlink_status_t *cstatus = mavlink_get_channel_status((mavlink_channel_t)(MAVLINK_COMM_0 + i));
147  if (cstatus != nullptr) {
148  if (all_zero) {
149  // disable signing
150  cstatus->signing = nullptr;
151  cstatus->signing_streams = nullptr;
152  } else {
153  cstatus->signing = &signing;
154  cstatus->signing_streams = &signing_streams;
155  }
156  }
157  }
158 }
159 
160 /*
161  update signing timestamp. This is called when we get GPS lock
162  timestamp_usec is since 1/1/1970 (the epoch)
163  */
164 void GCS_MAVLINK::update_signing_timestamp(uint64_t timestamp_usec)
165 {
166  uint64_t signing_timestamp = (timestamp_usec / (1000*1000ULL));
167  // this is the offset from 1/1/1970 to 1/1/2015
168  const uint64_t epoch_offset = 1420070400;
169  if (signing_timestamp > epoch_offset) {
170  signing_timestamp -= epoch_offset;
171  }
172 
173  // convert to 10usec units
174  signing_timestamp *= 100 * 1000ULL;
175 
176  // increase signing timestamp on any links that have signing
177  for (uint8_t i=0; i<MAVLINK_COMM_NUM_BUFFERS; i++) {
178  mavlink_channel_t chan = (mavlink_channel_t)(MAVLINK_COMM_0 + i);
179  mavlink_status_t *status = mavlink_get_channel_status(chan);
180  if (status && status->signing && status->signing->timestamp < signing_timestamp) {
181  status->signing->timestamp = signing_timestamp;
182  }
183  }
184 
185  // save to stable storage
186  save_signing_timestamp(true);
187 }
188 
189 
190 /*
191  save the signing timestamp periodically
192  */
193 void GCS_MAVLINK::save_signing_timestamp(bool force_save_now)
194 {
195  uint32_t now = AP_HAL::millis();
196  // we save the timestamp every 30s, unless forced by a GPS update
197  if (!force_save_now && now - last_signing_save_ms < 30*1000UL) {
198  return;
199  }
200 
201  last_signing_save_ms = now;
202 
203  struct SigningKey key;
204  if (!signing_key_load(key)) {
205  return;
206  }
207  bool need_save = false;
208 
209  for (uint8_t i=0; i<MAVLINK_COMM_NUM_BUFFERS; i++) {
210  mavlink_channel_t chan = (mavlink_channel_t)(MAVLINK_COMM_0 + i);
211  const mavlink_status_t *status = mavlink_get_channel_status(chan);
212  if (status && status->signing && status->signing->timestamp > key.timestamp) {
213  key.timestamp = status->signing->timestamp;
214  need_save = true;
215  }
216  }
217  if (need_save) {
218  // save updated key
219  signing_key_save(key);
220  }
221 }
222 
223 /*
224  return true if signing is enabled on this channel
225  */
227 {
228  const mavlink_status_t *status = mavlink_get_channel_status(chan);
229  if (status->signing && (status->signing->flags & MAVLINK_SIGNING_FLAG_SIGN_OUTGOING)) {
230  return true;
231  }
232  return false;
233 }
234 
235 /*
236  return packet overhead in bytes for a channel
237  */
238 uint8_t GCS_MAVLINK::packet_overhead_chan(mavlink_channel_t chan)
239 {
240  /*
241  reserve 100 bytes for parameters when a GCS fails to fetch a
242  parameter due to lack of buffer space. The reservation lasts 2
243  seconds
244  */
245  uint8_t reserved_space = 0;
246  if (reserve_param_space_start_ms != 0 &&
247  AP_HAL::millis() - reserve_param_space_start_ms < 2000) {
248  reserved_space = 100;
249  } else {
250  reserve_param_space_start_ms = 0;
251  }
252 
253  const mavlink_status_t *status = mavlink_get_channel_status(chan);
254  if (status->signing && (status->signing->flags & MAVLINK_SIGNING_FLAG_SIGN_OUTGOING)) {
255  return MAVLINK_NUM_NON_PAYLOAD_BYTES + MAVLINK_SIGNATURE_BLOCK_LEN + reserved_space;
256  }
257  return MAVLINK_NUM_NON_PAYLOAD_BYTES + reserved_space;
258 }
259 
AP_HAL::UARTDriver * console
Definition: HAL.h:110
Interface definition for the various Ground Control System.
static bool accept_unsigned_callback(const mavlink_status_t *status, uint32_t msgId)
Definition: GCS_Signing.cpp:97
uint64_t timestamp
Definition: GCS_Signing.cpp:31
virtual void printf(const char *,...) FMT_PRINTF(2
Definition: BetterStream.cpp:5
const AP_HAL::HAL & hal
-*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
Definition: AC_PID_test.cpp:14
uint32_t millis()
Definition: system.cpp:157
#define SIGNING_KEY_MAGIC
Definition: GCS_Signing.cpp:26
uint8_t secret_key[32]
Definition: GCS_Signing.cpp:32
#define ARRAY_SIZE(_arr)
Definition: AP_Common.h:80
AP_HAL::AnalogSource * chan
Definition: AnalogIn.cpp:8
uint32_t magic
Definition: GCS_Signing.cpp:30
static const uint32_t accept_list[]
Definition: GCS_Signing.cpp:92