3#include <QtCore/QCryptographicHash>
4#include <QtCore/QDateTime>
17 return status ? status->signing :
nullptr;
22 const mavlink_signing_t*
const signing = _channelSigningPtr(channel);
23 return signing ? signing->last_status : MAVLINK_SIGNING_STATUS_NONE;
43 return (message_id == MAVLINK_MSG_ID_RADIO_STATUS);
55bool pendingAcceptUnsignedCallback(
const mavlink_status_t* status, uint32_t message_id)
60 case MAVLINK_MSG_ID_RADIO_STATUS:
61 case MAVLINK_MSG_ID_HEARTBEAT:
62 case MAVLINK_MSG_ID_STATUSTEXT:
77 return pendingAcceptUnsignedCallback;
86 setup_signing.target_system = target_system.sysid;
87 setup_signing.target_component = target_system.compid;
89 if (!keyBytes.isEmpty() && keyBytes.size() >=
static_cast<qsizetype
>(
sizeof(setup_signing.secret_key))) {
91 const mavlink_signing_t*
const signing = _channelSigningPtr(channel);
92 const uint64_t channelTs = signing ? signing->timestamp : 0;
94 memcpy(setup_signing.secret_key, keyBytes.constData(),
sizeof(setup_signing.secret_key));
106 (void)mavlink_msg_setup_signing_encode_chan(srcSysId, srcCompId, channel, &message, &payload);
112 return (message.incompat_flags & MAVLINK_IFLAG_SIGNED) != 0;
118 message.incompat_flags |= MAVLINK_IFLAG_SIGNED;
120 message.incompat_flags &=
static_cast<uint8_t
>(~MAVLINK_IFLAG_SIGNED);
128 if (copy.magic == MAVLINK_STX) {
129 copy.incompat_flags &=
static_cast<uint8_t
>(~MAVLINK_IFLAG_SIGNED);
132 static_assert(MAVLINK_CORE_HEADER_LEN == 9,
"MAVLink2 core header layout changed — update CRC recomputation");
133 uint8_t header[MAVLINK_CORE_HEADER_LEN];
134 header[0] = copy.len;
135 header[1] = copy.incompat_flags;
136 header[2] = copy.compat_flags;
137 header[3] = copy.seq;
138 header[4] = copy.sysid;
139 header[5] = copy.compid;
140 header[6] =
static_cast<uint8_t
>(copy.msgid & 0xFF);
141 header[7] =
static_cast<uint8_t
>((copy.msgid >> 8) & 0xFF);
142 header[8] =
static_cast<uint8_t
>((copy.msgid >> 16) & 0xFF);
144 uint16_t checksum = crc_calculate(header, MAVLINK_CORE_HEADER_LEN);
145 crc_accumulate_buffer(&checksum, _MAV_PAYLOAD(©), copy.len);
146 crc_accumulate(mavlink_get_crc_extra(©), &checksum);
148 copy.checksum = checksum;
149 mavlink_ck_a(©) =
static_cast<uint8_t
>(checksum & 0xFF);
150 mavlink_ck_b(©) =
static_cast<uint8_t
>(checksum >> 8);
153 QByteArray buf(MAVLINK_MAX_PACKET_LEN, Qt::Uninitialized);
154 const uint16_t len = mavlink_msg_to_send_buffer(
reinterpret_cast<uint8_t*
>(buf.data()), ©);
166 const uint8_t* header =
reinterpret_cast<const uint8_t*
>(&message.magic);
167 const char* payload = _MAV_PAYLOAD(&message);
168 const uint8_t* sig = message.signature;
169 const uint8_t crc[2] = {
static_cast<uint8_t
>(message.checksum & 0xFF),
static_cast<uint8_t
>(message.checksum >> 8)};
171 const QByteArrayView parts[] = {
173 QByteArrayView(
reinterpret_cast<const char*
>(header), MAVLINK_NUM_HEADER_BYTES),
174 QByteArrayView(payload, message.len),
175 QByteArrayView(
reinterpret_cast<const char*
>(crc),
sizeof(crc)),
178 (void) QCryptographicHash::hashInto(QSpan<uchar>(hashBuf), QSpan<const QByteArrayView>(parts),
179 QCryptographicHash::Sha256);
191 _computeSignatureHash(key, message, hashBuf);
204 message.signature[0] = linkId;
205 for (
int i = 0; i < kTimestampBytes; ++i) {
206 message.signature[1 + i] =
static_cast<uint8_t
>((timestamp >> (8 * i)) & 0xFF);
210 _computeSignatureHash(key, message, hashBuf);
218 return verifySignature(QByteArrayView(
reinterpret_cast<const char*
>(key.data()), key.size()), message);
223 const mavlink_signing_t*
const signing = _channelSigningPtr(channel);
225 qCWarning(MAVLinkSigningLog) <<
"checkSigningLinkId: no signing struct on channel" << channel;
228 return (signing->link_id ==
static_cast<mavlink_channel_t>(message.signature[0]));
233 switch (_lastSigningStatus(channel)) {
234 case MAVLINK_SIGNING_STATUS_OK:
235 return QStringLiteral(
"OK");
236 case MAVLINK_SIGNING_STATUS_BAD_SIGNATURE:
237 return QStringLiteral(
"Bad Signature");
238 case MAVLINK_SIGNING_STATUS_NO_STREAMS:
239 return QStringLiteral(
"No Streams");
240 case MAVLINK_SIGNING_STATUS_TOO_MANY_STREAMS:
241 return QStringLiteral(
"Too Many Streams");
242 case MAVLINK_SIGNING_STATUS_OLD_TIMESTAMP:
243 return QStringLiteral(
"Stale Timestamp");
244 case MAVLINK_SIGNING_STATUS_REPLAY:
245 return QStringLiteral(
"Replay Detected");
246 case MAVLINK_SIGNING_STATUS_NONE:
255 if (!status || !status->signing_streams) {
258 return status->signing_streams->num_signing_streams;
263 switch (_lastSigningStatus(channel)) {
264 case MAVLINK_SIGNING_STATUS_BAD_SIGNATURE:
265 qCWarning(MAVLinkSigningLog) <<
"Channel" << channel <<
"signing failure: bad signature (key mismatch)";
267 case MAVLINK_SIGNING_STATUS_NO_STREAMS:
268 qCWarning(MAVLinkSigningLog) <<
"Channel" << channel <<
"signing failure: no signing streams table";
270 case MAVLINK_SIGNING_STATUS_TOO_MANY_STREAMS:
271 qCWarning(MAVLinkSigningLog) <<
"Channel" << channel <<
"signing failure: stream table full (>"
274 case MAVLINK_SIGNING_STATUS_OLD_TIMESTAMP:
275 qCWarning(MAVLinkSigningLog) <<
"Channel" << channel
276 <<
"signing failure: new stream with stale timestamp (>"
277 << MAVLINK_SIGNING_TIMESTAMP_LIMIT <<
"s old)";
279 case MAVLINK_SIGNING_STATUS_REPLAY:
280 qCWarning(MAVLinkSigningLog) <<
"Channel" << channel
281 <<
"signing failure: replay detected (repeated/old timestamp)";
283 case MAVLINK_SIGNING_STATUS_OK:
284 case MAVLINK_SIGNING_STATUS_NONE:
#define MAVLINK_MAX_SIGNING_STREAMS
mavlink_status_t * mavlink_get_channel_status(uint8_t chan)
struct __mavlink_setup_signing_t mavlink_setup_signing_t
struct __mavlink_message mavlink_message_t
#define QGC_LOGGING_CATEGORY(name, categoryStr)
QByteArray serializeUnsignedCopy(const mavlink_message_t &message)
static constexpr int kSignatureHashBytes
bool checkSigningLinkId(mavlink_channel_t channel, const mavlink_message_t &message)
bool encodeSetupSigning(mavlink_channel_t channel, uint8_t srcSysId, uint8_t srcCompId, mavlink_system_t target_system, QByteArrayView keyBytes, mavlink_message_t &message)
std::array< uint8_t, kSigningKeySize > SigningKey
std::array avoids QByteArray COW detach so secureZero() actually wipes the bytes.
QString signingStatusString(mavlink_channel_t channel)
void signMessage(QByteArrayView key, uint8_t linkId, uint64_t timestamp, mavlink_message_t &message)
bool verifySignature(QByteArrayView key, const mavlink_message_t &message)
Verify a key against a signed message's signature.
uint64_t currentSigningTimestampTicks()
Current signing timestamp in 10µs ticks since 2015-01-01.
void createSetupSigning(mavlink_channel_t channel, mavlink_system_t target_system, QByteArrayView keyBytes, mavlink_setup_signing_t &setup_signing)
Build a SETUP_SIGNING payload. Empty keyBytes produces a disable payload (zero key,...
bool secureConnectionAcceptUnsignedCallback(const mavlink_status_t *status, uint32_t message_id)
std::optional< SigningKey > makeSigningKey(QByteArrayView bytes)
Build a SigningKey from arbitrary bytes. Returns nullopt if input is the wrong size.
bool isMessageSigned(const mavlink_message_t &message)
Returns true if the message has a MAVLink2 signature.
mavlink_accept_unsigned_t callbackForPolicy(UnsignedAcceptancePolicy policy)
Maps a high-level policy to the underlying libmavlink callback.
void logSigningFailure(mavlink_channel_t channel)
static constexpr int kSigningKeySize
void setMessageSigned(mavlink_message_t &message, bool isSigned)
Set or clear the MAVLink2 signature incompatibility flag on a message.
static constexpr int kSignaturePrefixBytes
bool insecureConnectionAcceptUnsignedCallback(const mavlink_status_t *status, uint32_t message_id)
int signingStreamCount(mavlink_channel_t channel)