Line data Source code
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_config.h" 19 : 20 : #if HAL_GCS_ENABLED 21 : 22 : #include "GCS.h" 23 : 24 : #if AP_MAVLINK_SIGNING_ENABLED 25 : 26 : extern const AP_HAL::HAL& hal; 27 : 28 : // storage object 29 : StorageAccess GCS_MAVLINK::_signing_storage(StorageManager::StorageKeys); 30 : 31 : // magic for versioning of the structure 32 : #define SIGNING_KEY_MAGIC 0x3852fcd1 33 : 34 : // structure stored in FRAM 35 : struct SigningKey { 36 : uint32_t magic; 37 : uint64_t timestamp; 38 : uint8_t secret_key[32]; 39 : }; 40 : 41 : // shared signing_streams structure 42 : mavlink_signing_streams_t GCS_MAVLINK::signing_streams; 43 : 44 : // last time we saved the timestamp 45 : uint32_t GCS_MAVLINK::last_signing_save_ms; 46 : 47 0 : bool GCS_MAVLINK::signing_key_save(const struct SigningKey &key) 48 : { 49 0 : if (_signing_storage.size() < sizeof(key)) { 50 0 : return false; 51 : } 52 0 : return _signing_storage.write_block(0, &key, sizeof(key)); 53 : } 54 : 55 1359871 : bool GCS_MAVLINK::signing_key_load(struct SigningKey &key) 56 : { 57 1359871 : if (_signing_storage.size() < sizeof(key)) { 58 0 : return false; 59 : } 60 1359871 : if (!_signing_storage.read_block(&key, 0, sizeof(key))) { 61 0 : return false; 62 : } 63 1359871 : if (key.magic != SIGNING_KEY_MAGIC) { 64 1359871 : return false; 65 : } 66 0 : return true; 67 : } 68 : 69 : /* 70 : handle a setup_signing message 71 : */ 72 0 : void GCS_MAVLINK::handle_setup_signing(const mavlink_message_t &msg) const 73 : { 74 : // setting up signing key when armed generally not useful / 75 : // possibly not a good idea 76 0 : if (hal.util->get_soft_armed()) { 77 0 : send_text(MAV_SEVERITY_WARNING, "ERROR: Won't setup signing when armed"); 78 0 : return; 79 : } 80 : 81 : // decode 82 : mavlink_setup_signing_t packet; 83 0 : mavlink_msg_setup_signing_decode(&msg, &packet); 84 : 85 0 : struct SigningKey key {}; 86 0 : key.magic = SIGNING_KEY_MAGIC; 87 0 : key.timestamp = packet.initial_timestamp; 88 0 : memcpy(key.secret_key, packet.secret_key, 32); 89 : 90 0 : if (!signing_key_save(key)) { 91 0 : send_text(MAV_SEVERITY_WARNING, "ERROR: Failed to save signing key"); 92 0 : return; 93 : } 94 : 95 : // activate it immediately on all links: 96 0 : for (uint8_t i=0; i<MAVLINK_COMM_NUM_BUFFERS; i++) { 97 0 : GCS_MAVLINK *backend = gcs().chan(i); 98 0 : if (backend == nullptr) { 99 0 : return; 100 : } 101 0 : backend->load_signing_key(); 102 : } 103 : } 104 : 105 : 106 : /* 107 : callback to accept unsigned (or incorrectly signed) packets 108 : */ 109 : extern "C" { 110 : 111 : static const uint32_t accept_list[] = { 112 : MAVLINK_MSG_ID_RADIO_STATUS, 113 : MAVLINK_MSG_ID_RADIO 114 : }; 115 : 116 0 : static bool accept_unsigned_callback(const mavlink_status_t *status, uint32_t msgId) 117 : { 118 0 : if (status == mavlink_get_channel_status(MAVLINK_COMM_0)) { 119 : // always accept channel 0, assumed to be secure channel. This 120 : // is USB on ChibiOS boards 121 0 : return true; 122 : } 123 0 : for (uint8_t i=0; i<ARRAY_SIZE(accept_list); i++) { 124 0 : if (accept_list[i] == msgId) { 125 0 : return true; 126 : } 127 : } 128 0 : return false; 129 : } 130 : } 131 : 132 : /* 133 : load signing key 134 : */ 135 6331 : void GCS_MAVLINK::load_signing_key(void) 136 : { 137 : struct SigningKey key; 138 6331 : if (option_enabled(Option::MAVLINK2_SIGNING_DISABLED) || !signing_key_load(key)) { 139 6331 : return; 140 : } 141 0 : memcpy(signing.secret_key, key.secret_key, 32); 142 0 : signing.link_id = (uint8_t)chan; 143 : // use a timestamp 1 minute past the last recorded 144 : // timestamp. Combined with saving the key once every 30s this 145 : // prevents a window for replay attacks 146 0 : signing.timestamp = key.timestamp + 60UL * 100UL * 1000UL; 147 0 : signing.flags = MAVLINK_SIGNING_FLAG_SIGN_OUTGOING; 148 0 : signing.accept_unsigned_callback = accept_unsigned_callback; 149 : 150 : // if timestamp and key are all zero then we disable signing 151 0 : bool all_zero = (key.timestamp == 0); 152 0 : for (uint8_t i=0; i<sizeof(key.secret_key); i++) { 153 0 : if (signing.secret_key[i] != 0) { 154 0 : all_zero = false; 155 0 : break; 156 : } 157 : } 158 0 : if (all_zero) { 159 : // disable signing 160 0 : _channel_status.signing = nullptr; 161 0 : _channel_status.signing_streams = nullptr; 162 : } else { 163 0 : _channel_status.signing = &signing; 164 0 : _channel_status.signing_streams = &signing_streams; 165 : } 166 : } 167 : 168 : /* 169 : update signing timestamp. This is called when we get GPS lock 170 : timestamp_usec is since 1/1/1970 (the epoch) 171 : */ 172 1352867 : void GCS_MAVLINK::update_signing_timestamp(uint64_t timestamp_usec) 173 : { 174 1352867 : uint64_t signing_timestamp = (timestamp_usec / (1000*1000ULL)); 175 : // this is the offset from 1/1/1970 to 1/1/2015 176 1352867 : const uint64_t epoch_offset = 1420070400; 177 1352867 : if (signing_timestamp > epoch_offset) { 178 1352867 : signing_timestamp -= epoch_offset; 179 : } 180 : 181 : // convert to 10usec units 182 1352867 : signing_timestamp *= 100 * 1000ULL; 183 : 184 : // increase signing timestamp on any links that have signing 185 22998579 : for (uint8_t i=0; i<MAVLINK_COMM_NUM_BUFFERS; i++) { 186 21645712 : mavlink_channel_t chan = (mavlink_channel_t)(MAVLINK_COMM_0 + i); 187 21645712 : mavlink_status_t *status = mavlink_get_channel_status(chan); 188 21645712 : if (status && status->signing && status->signing->timestamp < signing_timestamp) { 189 0 : status->signing->timestamp = signing_timestamp; 190 : } 191 : } 192 : 193 : // save to stable storage 194 1352867 : save_signing_timestamp(true); 195 1352867 : } 196 : 197 : 198 : /* 199 : save the signing timestamp periodically 200 : */ 201 1376497 : void GCS_MAVLINK::save_signing_timestamp(bool force_save_now) 202 : { 203 1376497 : uint32_t now = AP_HAL::millis(); 204 : // we save the timestamp every 30s, unless forced by a GPS update 205 1376497 : if (!force_save_now && now - last_signing_save_ms < 30*1000UL) { 206 1376497 : return; 207 : } 208 : 209 1353540 : last_signing_save_ms = now; 210 : 211 : struct SigningKey key; 212 1353540 : if (!signing_key_load(key)) { 213 1353540 : return; 214 : } 215 0 : bool need_save = false; 216 : 217 0 : for (uint8_t i=0; i<MAVLINK_COMM_NUM_BUFFERS; i++) { 218 0 : mavlink_channel_t chan = (mavlink_channel_t)(MAVLINK_COMM_0 + i); 219 0 : const mavlink_status_t *status = mavlink_get_channel_status(chan); 220 0 : if (status && status->signing && status->signing->timestamp > key.timestamp) { 221 0 : key.timestamp = status->signing->timestamp; 222 0 : need_save = true; 223 : } 224 : } 225 0 : if (need_save) { 226 : // save updated key 227 0 : signing_key_save(key); 228 : } 229 : } 230 : 231 : /* 232 : return true if signing is enabled on this channel 233 : */ 234 311551 : bool GCS_MAVLINK::signing_enabled(void) const 235 : { 236 311551 : const mavlink_status_t *status = mavlink_get_channel_status(chan); 237 311551 : if ((status != nullptr) && status->signing && (status->signing->flags & MAVLINK_SIGNING_FLAG_SIGN_OUTGOING)) { 238 0 : return true; 239 : } 240 311551 : return false; 241 : } 242 : #endif // AP_MAVLINK_SIGNING_ENABLED 243 : 244 : /* 245 : return packet overhead in bytes for a channel 246 : */ 247 256264032 : uint8_t GCS_MAVLINK::packet_overhead_chan(mavlink_channel_t chan) 248 : { 249 : /* 250 : reserve 100 bytes for parameters when a GCS fails to fetch a 251 : parameter due to lack of buffer space. The reservation lasts 2 252 : seconds 253 : */ 254 256264032 : uint8_t reserved_space = 0; 255 256264032 : if (reserve_param_space_start_ms != 0 && 256 0 : AP_HAL::millis() - reserve_param_space_start_ms < 2000) { 257 0 : reserved_space = 100; 258 : } else { 259 256264032 : reserve_param_space_start_ms = 0; 260 : } 261 : 262 256264032 : const mavlink_status_t *status = mavlink_get_channel_status(chan); 263 256264032 : if ((status != nullptr) && status->signing && (status->signing->flags & MAVLINK_SIGNING_FLAG_SIGN_OUTGOING)) { 264 0 : return MAVLINK_NUM_NON_PAYLOAD_BYTES + MAVLINK_SIGNATURE_BLOCK_LEN + reserved_space; 265 : } 266 256264032 : return MAVLINK_NUM_NON_PAYLOAD_BYTES + reserved_space; 267 : } 268 : 269 : #if !AP_MAVLINK_SIGNING_ENABLED 270 : 271 : void GCS_MAVLINK::handle_setup_signing(const mavlink_message_t &msg) const 272 : { 273 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "Signing is not enabled in this firmware"); 274 : } 275 : 276 : #endif // !AP_MAVLINK_SIGNING_ENABLED 277 : 278 : #endif // HAL_GCS_ENABLED