summaryrefslogtreecommitdiff
path: root/unit
diff options
context:
space:
mode:
authorBrian Gix <brian.gix@intel.com>2020-10-08 11:09:30 -0700
committerBrian Gix <brian.gix@gmail.com>2023-01-30 16:14:41 -0800
commit2ff937b6aa5030f4330851e8c1140af88c03c752 (patch)
treeb0d419288177c88c4e1824f3f8c5c331b8e73001 /unit
parent9923c09de57e558a8b85df12bed31b9be4d2ec9f (diff)
downloadbluez-2ff937b6aa5030f4330851e8c1140af88c03c752.tar.gz
unit/mesh: Add unit testing of Mesh Private Beaconing
This includes the Sample Data from the Mesh Profile specification v1.1, and validates that the beacon crypto functions work as expected.
Diffstat (limited to 'unit')
-rw-r--r--unit/test-mesh-crypto.c182
1 files changed, 147 insertions, 35 deletions
diff --git a/unit/test-mesh-crypto.c b/unit/test-mesh-crypto.c
index f9b7d81da..39632d973 100644
--- a/unit/test-mesh-crypto.c
+++ b/unit/test-mesh-crypto.c
@@ -633,6 +633,36 @@ static const struct mesh_crypto_test s8_4_3 = {
.beacon = "01003ecaff672f673370123456788ea261582f364f6f",
};
+static const struct mesh_crypto_test s8_4_6_1 = {
+ .name = "8.4.6.1 Private Beacon IVU",
+
+ .net_key = "f7a2a44f8e8a8029064f173ddc1e2b00",
+ .iv_index = 0x1010abcd,
+
+ .enc_key = "6be76842460b2d3a5850d4698409f1bb",
+ .rand = "435f18f85cf78a3121f58478a5",
+
+ .beacon_type = 0x02,
+ .beacon_flags = 0x02,
+ .beacon_cmac = "f3174f022a514741",
+ .beacon = "02435f18f85cf78a3121f58478a561e488e7cbf3174f022a514741",
+};
+
+static const struct mesh_crypto_test s8_4_6_2 = {
+ .name = "8.4.6.2 Private Beacon IVU Complete",
+
+ .net_key = "3bbb6f1fbd53e157417f308ce7aec58f",
+ .iv_index = 0x00000000,
+
+ .enc_key = "ca478cdac626b7a8522d7272dd124f26",
+ .rand = "1b998f82927535ea6f3076f422",
+
+ .beacon_type = 0x02,
+ .beacon_flags = 0x00,
+ .beacon_cmac = "2f0ffb94cf97f881",
+ .beacon = "021b998f82927535ea6f3076f422ce827408ab2f0ffb94cf97f881",
+};
+
static const struct mesh_crypto_test s8_6_2 = {
.name = "8.6.2 Service Data using Node Identity",
@@ -683,6 +713,17 @@ static void verify_data(const char *label, unsigned int indent,
l_free(str);
}
+static void verify_bool(const char *label, unsigned int indent,
+ bool sample, bool data)
+{
+ l_info("%-20s =%*c%s", label, 1 + (indent * 2), ' ',
+ sample ? "true" : "false");
+ l_info("%-20s %*c%s => %s", "", 1 + (indent * 2), ' ',
+ data ? "true" : "false",
+ EVALNUM(sample, data));
+ EXITNUM(sample, data);
+}
+
static void verify_bool_not_both(const char *label, unsigned int indent,
bool sample, bool data)
{
@@ -796,10 +837,11 @@ static void check_encrypt_segment(const struct mesh_crypto_test *keys,
uint32_t hdr;
uint64_t net_mic64, net_mic32;
size_t net_msg_len;
+ bool status;
uint8_t key_aid = keys->key_aid | (keys->akf ? KEY_ID_AKF : 0x00);
if (keys->ctl) {
- mesh_crypto_packet_build(keys->ctl, keys->net_ttl,
+ status = mesh_crypto_packet_build(keys->ctl, keys->net_ttl,
keys->net_seq[0],
keys->net_src, keys->net_dst,
keys->opcode,
@@ -809,7 +851,7 @@ static void check_encrypt_segment(const struct mesh_crypto_test *keys,
enc_msg, len,
packet, &packet_len);
} else {
- mesh_crypto_packet_build(keys->ctl, keys->net_ttl,
+ status = mesh_crypto_packet_build(keys->ctl, keys->net_ttl,
keys->net_seq[0],
keys->net_src, keys->net_dst,
keys->opcode,
@@ -822,6 +864,10 @@ static void check_encrypt_segment(const struct mesh_crypto_test *keys,
l_info(COLOR_YELLOW "Segment-%d" COLOR_OFF, seg);
+ verify_bool("Crypto packet build", 0, true, status);
+ if (!status)
+ return;
+
hdr = l_get_be32(packet + 9);
verify_uint8("SEG", 9, keys->segmented << (SEG_HDR_SHIFT % 8),
packet[9] & (1 << (SEG_HDR_SHIFT % 8)));
@@ -870,15 +916,20 @@ static void check_encrypt_segment(const struct mesh_crypto_test *keys,
net_msg_len = len + 2;
show_data("TransportPayload", 7, packet + 7, net_msg_len);
- mesh_crypto_packet_encrypt(packet, packet_len,
+ status = mesh_crypto_packet_encrypt(packet, packet_len,
enc_key,
keys->iv_index, false,
keys->ctl, keys->net_ttl,
keys->net_seq[0],
keys->net_src);
+ verify_bool("Crypto packet encrypt", 0, true, status);
+ if (!status)
+ return;
+
mesh_crypto_privacy_counter(keys->iv_index, packet + 7, priv_rand);
+
l_info("");
show_uint32("IVindex", 0, keys->iv_index);
verify_data("NetworkNonce", 0, keys->net_nonce[0], net_nonce, 13);
@@ -907,10 +958,15 @@ static void check_encrypt_segment(const struct mesh_crypto_test *keys,
}
show_data("PreObsPayload", 1, packet + 1, 6 + net_msg_len);
- mesh_crypto_network_obfuscate(packet, priv_key,
+ status = mesh_crypto_network_obfuscate(packet, priv_key,
keys->iv_index,
keys->ctl, keys->net_ttl,
keys->net_seq[0], keys->net_src);
+
+ verify_bool("Crypto network obfuscate", 0, true, status);
+ if (!status)
+ return;
+
show_data("PostObsPayload", 1, packet + 1, 6 + net_msg_len);
packet[0] = (keys->iv_index & 0x01) << 7 | nid;
@@ -926,7 +982,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
uint8_t *dev_key;
uint8_t *app_key;
uint8_t *net_key;
- uint8_t nid;
+ uint8_t nid = 0;
uint8_t enc_key[16];
uint8_t priv_key[16];
uint8_t net_nonce[13];
@@ -949,6 +1005,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
uint8_t packet_len;
uint16_t i, seg_max, seg_len = 0;
uint32_t seqZero, hdr;
+ bool status;
l_info(COLOR_BLUE "[Encrypt %s]" COLOR_OFF, keys->name);
verify_bool_not_both("CTL && Segmented", 0, keys->ctl, keys->segmented);
@@ -960,8 +1017,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
show_data("NetworkKey", 0, net_key, 16);
- if (keys->akf) {
- mesh_crypto_k4(app_key, &key_aid);
+ if (keys->akf && mesh_crypto_k4(app_key, &key_aid)) {
key_aid |= KEY_ID_AKF;
} else {
key_aid = 0;
@@ -1034,7 +1090,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
seg_max = SEG_MAX(keys->segmented, app_msg_len + 8);
enc_msg = l_malloc(app_msg_len + 8);
- mesh_crypto_payload_encrypt(aad, app_msg,
+ status = mesh_crypto_payload_encrypt(aad, app_msg,
enc_msg, app_msg_len,
keys->net_src, keys->net_dst, key_aid,
keys->app_seq, keys->iv_index,
@@ -1044,7 +1100,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
seg_max = SEG_MAX(keys->segmented, app_msg_len + 4);
enc_msg = l_malloc(app_msg_len + 4);
- mesh_crypto_payload_encrypt(aad, app_msg,
+ status = mesh_crypto_payload_encrypt(aad, app_msg,
enc_msg, app_msg_len,
keys->net_src, keys->net_dst, key_aid,
keys->app_seq, keys->iv_index,
@@ -1052,6 +1108,10 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
keys->akf ? app_key : dev_key);
}
+ verify_bool("Crypto payload encrypt", 0, true, status);
+ if (!status)
+ return;
+
if (keys->dev_key && !keys->akf)
show_data("DeviceKey", 0, dev_key, 16);
@@ -1097,7 +1157,8 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
}
if (keys->ctl) {
- mesh_crypto_packet_build(keys->ctl, keys->net_ttl,
+ status = mesh_crypto_packet_build(keys->ctl,
+ keys->net_ttl,
keys->net_seq[i],
keys->net_src, keys->net_dst,
keys->opcode,
@@ -1107,7 +1168,8 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
enc_msg + 1, seg_len,
packet, &packet_len);
} else {
- mesh_crypto_packet_build(keys->ctl, keys->net_ttl,
+ status = mesh_crypto_packet_build(keys->ctl,
+ keys->net_ttl,
keys->net_seq[i],
keys->net_src, keys->net_dst,
keys->opcode,
@@ -1120,6 +1182,10 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
if (seg_max) l_info(COLOR_YELLOW "Segment-%d" COLOR_OFF, i);
+ verify_bool("Crypto packet build", 0, true, status);
+ if (!status)
+ return;
+
hdr = l_get_be32(packet + 9);
verify_uint8("SEG", 9, keys->segmented << (SEG_HDR_SHIFT % 8),
packet[9] & (1 << (SEG_HDR_SHIFT % 8)));
@@ -1193,12 +1259,16 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
net_msg_len = seg_len + 2;
show_data("TransportPayload", 7, packet + 7, net_msg_len);
- mesh_crypto_packet_encrypt(packet, packet_len, enc_key,
+ status = mesh_crypto_packet_encrypt(packet, packet_len, enc_key,
keys->iv_index, false,
keys->ctl, keys->net_ttl,
keys->net_seq[i],
keys->net_src);
+ verify_bool("Crypto packet encrypt", 0, true, status);
+ if (!status)
+ return;
+
mesh_crypto_privacy_counter(keys->iv_index, packet + 7,
priv_rand);
@@ -1232,11 +1302,15 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
}
show_data("PreObsPayload", 1, packet + 1, 6 + net_msg_len);
- mesh_crypto_network_obfuscate(packet, priv_key,
+ status = mesh_crypto_network_obfuscate(packet, priv_key,
keys->iv_index,
keys->ctl, keys->net_ttl,
keys->net_seq[i], keys->net_src);
+ verify_bool("Crypto network obfuscate", 0, true, status);
+ if (!status)
+ return;
+
show_data("PostObsPayload", 1, packet + 1, 6 + net_msg_len);
packet[0] = (keys->iv_index & 0x01) << 7 | nid;
@@ -1265,19 +1339,20 @@ static void check_decrypt_segment(const struct mesh_crypto_test *keys,
uint8_t net_clr[29];
uint64_t net_mic64, calc_net_mic64;
uint32_t hdr, net_mic32, calc_net_mic32;
- bool ctl, segmented, relay, szmic, key_akf;
+ bool ctl, segmented, relay, szmic, key_akf, status;
uint8_t ttl, opcode, key_aid, segO, segN;
uint32_t seq;
uint16_t src, dst, seqZero;
memcpy(net_clr, pkt, pkt_len);
show_data("NetworkMessage", 0, pkt, pkt_len);
- mesh_crypto_packet_decode(pkt, pkt_len,
+ status = mesh_crypto_packet_decode(pkt, pkt_len,
false, net_clr, keys->iv_index,
enc_key, priv_key);
show_data("Decoded", 0, net_clr, pkt_len);
- mesh_crypto_packet_parse(net_clr, pkt_len,
+ if (status)
+ status = mesh_crypto_packet_parse(net_clr, pkt_len,
&ctl, &ttl, &seq,
&src, &dst,
NULL, &opcode,
@@ -1286,6 +1361,10 @@ static void check_decrypt_segment(const struct mesh_crypto_test *keys,
&segO, &segN,
&msg, &msg_len);
+ verify_bool("Crypto Decode-Parse", 0, true, status);
+ if (!status)
+ return;
+
if (ctl) {
net_mic64 = l_get_be64(pkt + pkt_len - 8);
show_data("EncryptedPayload", 7, pkt + 7, pkt_len - 7 - 8);
@@ -1416,7 +1495,7 @@ static void check_decrypt(const struct mesh_crypto_test *keys)
uint16_t app_msg_len = 0;
uint32_t calc_net_mic32, net_mic32 = 0;
uint64_t calc_net_mic64, net_mic64 = 0;
- bool net_ctl, net_segmented, net_rly, net_akf;
+ bool net_ctl, net_segmented, net_rly, net_akf, status;
uint8_t net_aid, net_ttl, nid, net_segO, net_segN = 0;
uint32_t net_seq, hdr, seqZero = 0;
uint16_t net_src, net_dst;
@@ -1501,8 +1580,14 @@ static void check_decrypt(const struct mesh_crypto_test *keys)
net_msg = packet + 7;
net_msg_len = packet_len - 7;
- mesh_crypto_network_clarify(packet, priv_key, keys->iv_index,
- &net_ctl, &net_ttl, &net_seq, &net_src);
+ status = mesh_crypto_network_clarify(packet, priv_key,
+ keys->iv_index, &net_ctl, &net_ttl, &net_seq,
+ &net_src);
+
+ verify_bool("Crypto Clarify", 0, true, status);
+ if (!status)
+ return;
+
show_str("Packet", 0, keys->packet[i]);
@@ -1731,42 +1816,67 @@ static void check_beacon(const struct mesh_crypto_test *keys)
{
uint8_t *net_key;
uint8_t *beacon_cmac;
- uint8_t beacon[22];
+ uint8_t *random = NULL;
+ uint8_t beacon[29];
uint8_t enc_key[16];
uint8_t net_id[8];
uint8_t cmac[8];
- uint64_t cmac_tmp;
+ uint64_t cmac_tmp = 0;
+
+ if (keys->beacon_type < 1 || keys->beacon_type > 2)
+ verify_uint8("Unknown Beacon", 0, true,
+ (keys->beacon_type >= 1 || keys->beacon_type <= 2));
net_key = l_util_from_hexstring(keys->net_key, NULL);
beacon_cmac = l_util_from_hexstring(keys->beacon_cmac, NULL);
- mesh_crypto_nkbk(net_key, enc_key);
+ if (keys->beacon_type == 1) {
+ mesh_crypto_nkbk(net_key, enc_key);
+ } else {
+ mesh_crypto_nkpk(net_key, enc_key);
+ random = l_util_from_hexstring(keys->rand, NULL);
+ }
+
mesh_crypto_k3(net_key, net_id);
l_info(COLOR_BLUE "[%s]" COLOR_OFF, keys->name);
verify_data("NetworkKey", 0, keys->net_key, net_key, 16);
+ show_uint8("Beacon Flags", 0, keys->beacon_flags);
show_uint32("IVindex", 0, keys->iv_index);
verify_data("BeaconKey", 0, keys->enc_key, enc_key, 16);
- verify_data("NetworkID", 0, keys->net_id, net_id, 8);
beacon[0] = keys->beacon_type;
- beacon[1] = keys->beacon_flags;
- memcpy(beacon + 2, net_id, 8);
- l_put_be32(keys->iv_index, beacon + 10);
- mesh_crypto_beacon_cmac(enc_key, net_id, keys->iv_index,
- !!(keys->beacon_flags & 0x01),
- !!(keys->beacon_flags & 0x02),
- &cmac_tmp);
-
- l_put_be64(cmac_tmp, cmac);
- l_put_be64(cmac_tmp, beacon + 14);
- verify_data("BeaconCMAC", 0, keys->beacon_cmac, cmac, 8);
- verify_data("Beacon", 0, keys->beacon, beacon, sizeof(beacon));
+ if (keys->beacon_type == 1) {
+ verify_data("NetworkID", 0, keys->net_id, net_id, 8);
+ beacon[1] = keys->beacon_flags;
+ memcpy(beacon + 2, net_id, 8);
+ l_put_be32(keys->iv_index, beacon + 10);
+ mesh_crypto_beacon_cmac(enc_key, net_id, keys->iv_index,
+ !!(keys->beacon_flags & 0x01),
+ !!(keys->beacon_flags & 0x02),
+ &cmac_tmp);
+
+ l_put_be64(cmac_tmp, cmac);
+ l_put_be64(cmac_tmp, beacon + 14);
+ verify_data("BeaconCMAC", 0, keys->beacon_cmac, cmac, 8);
+ verify_data("SNBeacon", 0, keys->beacon, beacon, 22);
+ } else {
+ show_data("Random", 0, random, sizeof(random));
+ memcpy(beacon + 1, random, 13);
+ beacon[14] = keys->beacon_flags;
+ l_put_be32(keys->iv_index, beacon + 15);
+ mesh_crypto_aes_ccm_encrypt(random, enc_key, NULL, 0,
+ beacon + 14, 5,
+ beacon + 14, NULL, 8);
+ verify_data("BeaconMIC", 0, keys->beacon_cmac, beacon + 19, 8);
+ verify_data("PrivBeacon", 0, keys->beacon, beacon, 27);
+ }
l_info("");
+ l_free(random);
l_free(beacon_cmac);
l_free(net_key);
}
@@ -2071,6 +2181,8 @@ int main(int argc, char *argv[])
/* Section 8.4 Beacon Sample Data */
check_beacon(&s8_4_3);
+ check_beacon(&s8_4_6_1);
+ check_beacon(&s8_4_6_2);
/* Section 8.6 Mesh Proxy Service sample data */
check_id_beacon(&s8_6_2);