[thread-cert] refactor case 8.1.2, 8.2.1 and 8.2.2 using pktverify (#5411)

This commit is contained in:
Jing Ma
2020-08-26 21:18:07 -07:00
committed by GitHub
parent 35ede082ac
commit dc133baa68
5 changed files with 173 additions and 12 deletions
@@ -30,6 +30,8 @@
import unittest
import thread_cert
from pktverify.consts import MLE_DISCOVERY_RESPONSE, HANDSHAKE_CLIENT_HELLO, HANDSHAKE_SERVER_HELLO, HANDSHAKE_SERVER_KEY_EXCHANGE, HANDSHAKE_SERVER_HELLO_DONE, HANDSHAKE_CLIENT_KEY_EXCHANGE, HANDSHAKE_HELLO_VERIFY_REQUEST, NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_NAME_TLV, NM_STEERING_DATA_TLV, NM_COMMISSIONER_UDP_PORT_TLV, NM_JOINER_UDP_PORT_TLV, NM_DISCOVERY_RESPONSE_TLV, CONTENT_CHANGE_CIPHER_SPEC, CONTENT_ALERT, CONTENT_HANDSHAKE
from pktverify.packet_verifier import PacketVerifier
COMMISSIONER = 1
JOINER = 2
@@ -40,12 +42,14 @@ class Cert_8_1_02_Commissioning(thread_cert.TestCase):
TOPOLOGY = {
COMMISSIONER: {
'masterkey': 'deadbeefdeadbeefdeadbeefdeadbeef',
'name': 'COMMISSIONER',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rsdn',
'panid': 0xface
},
JOINER: {
'masterkey': '00112233445566778899aabbccddeeff',
'name': 'JOINER',
'masterkey': 'deadbeefdeadbeefdeadbeefdeadbeef',
'mode': 'rsdn',
'router_selection_jitter': 1
},
@@ -63,10 +67,50 @@ class Cert_8_1_02_Commissioning(thread_cert.TestCase):
self.nodes[JOINER].interface_up()
self.nodes[JOINER].joiner_start('10DKSP')
self.simulator.go(10)
self.assertNotEqual(
self.nodes[JOINER].get_masterkey(),
self.nodes[COMMISSIONER].get_masterkey(),
)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
COMMISSIONER = pv.vars['COMMISSIONER']
_cpkts = pkts.filter_wpan_src64(COMMISSIONER)
_cpkts2 = pkts.filter_wpan_dst64(COMMISSIONER)
# Step 3: Verify the following details occur in the exchange between
# Joiner_1 and the Commissioner
# 1. UDP port (Specified by the Commissioner: in Discovery Response) is used as destination port for UDP datagrams from Joiner_1 to the Commissioner.
_cpkts.filter_mle_cmd(MLE_DISCOVERY_RESPONSE).must_next().must_verify(
lambda p: {
NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_NAME_TLV, NM_STEERING_DATA_TLV, NM_COMMISSIONER_UDP_PORT_TLV,
NM_JOINER_UDP_PORT_TLV, NM_DISCOVERY_RESPONSE_TLV
} == set(p.thread_meshcop.tlv.type))
# 2. Joiner_1 sends an initial DTLS-ClientHello handshake record to the Commissioner
_cpkts2.range(_cpkts.index).filter(lambda p: p.dtls.handshake.type == [HANDSHAKE_CLIENT_HELLO]).must_next()
# 3. The Commissioner must correctly receive the initial DTLS-ClientHello handshake record and send a DTLS-HelloVerifyRequest handshake record to Joiner_1
_pkt = _cpkts.range(
_cpkts2.index).filter(lambda p: p.dtls.handshake.type == [HANDSHAKE_HELLO_VERIFY_REQUEST]).must_next()
_pkt.must_verify(lambda p: p.dtls.handshake.cookie is not None)
# 4. Joiner_1 receives the DTLS-HelloVerifyRequest handshake record and sends a subsequent DTLS-ClientHello handshake record in one UDP datagram to the Commissioner
# 5. Verify that both DTLS-HelloVerifyRequest and subsequent DTLS-ClientHello contain the same cookie
_cpkts2.filter(lambda p: p.dtls.handshake.type == [HANDSHAKE_CLIENT_HELLO]).must_next().must_verify(
lambda p: p.dtls.handshake.cookie == _pkt.dtls.handshake.cookie)
# 6. The Commissioner must correctly receive the subsequent DTLSClientHello handshake record and then send, in order, DTLSServerHello, DTLS-ServerKeyExchange and DTLSServerHelloDone handshake records to Joiner_1
_cpkts.filter(
lambda p: p.dtls.handshake.type ==
[HANDSHAKE_SERVER_HELLO, HANDSHAKE_SERVER_KEY_EXCHANGE, HANDSHAKE_SERVER_HELLO_DONE]).must_next()
# 7. Joiner_1 receives the DTLS-ServerHello, DTLSServerKeyExchange and DTLS-ServerHelloDone handshake records and sends, in order, a DTLS-ClientKeyExchange handshake record, a DTLS-ChangeCipherSpec record and an encrypted DTLS-Finished handshake record to the Commissioner.
_cpkts2.filter(lambda p: p.dtls.handshake.type == [HANDSHAKE_CLIENT_KEY_EXCHANGE]).must_next().must_verify(
lambda p: p.dtls.handshake.type == [HANDSHAKE_CLIENT_KEY_EXCHANGE] and set(
p.dtls.record.content_type) == {CONTENT_CHANGE_CIPHER_SPEC, CONTENT_HANDSHAKE})
# 8. The Commissioner must receive the DTLS-ClientKeyExchange handshake record, the DTLS-ChangeCipherSpec and the encrypted DTLS-Finished handshake record, and then send a DTLS-Alert record with error code 20 (bad record MAC) - in one UDP datagram - to Joiner_1
_cpkts.filter(
lambda p: p.dtls.record.content_type == [CONTENT_ALERT] and p.dtls.alert_message.desc == 20).must_next()
if __name__ == '__main__':
@@ -30,6 +30,8 @@
import unittest
import thread_cert
from pktverify.consts import MLE_CHILD_ID_RESPONSE, MLE_DISCOVERY_RESPONSE, HANDSHAKE_CLIENT_HELLO, NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_NAME_TLV, NM_STEERING_DATA_TLV, NM_COMMISSIONER_UDP_PORT_TLV, NM_JOINER_UDP_PORT_TLV, NM_DISCOVERY_RESPONSE_TLV, RLY_RX_URI, RLY_TX_URI
from pktverify.packet_verifier import PacketVerifier
COMMISSIONER = 1
JOINER_ROUTER = 2
@@ -41,17 +43,20 @@ class Cert_8_2_01_JoinerRouter(thread_cert.TestCase):
TOPOLOGY = {
COMMISSIONER: {
'masterkey': 'deadbeefdeadbeefdeadbeefdeadbeef',
'name': 'COMMISSIONER',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rsdn',
'panid': 0xface,
'router_selection_jitter': 1
},
JOINER_ROUTER: {
'name': 'JOINER_ROUTER',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rsdn',
'router_selection_jitter': 1
},
JOINER: {
'name': 'JOINER',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rsdn',
'router_selection_jitter': 1
@@ -99,6 +104,40 @@ class Cert_8_2_01_JoinerRouter(thread_cert.TestCase):
self.nodes[JOINER].thread_start()
self.simulator.go(5)
self.assertEqual(self.nodes[JOINER].get_state(), 'router')
self.collect_rloc16s()
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
COMMISSIONER = pv.vars['COMMISSIONER']
_cpkts = pkts.filter_wpan_src64(COMMISSIONER)
_cpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
# Step 3: Verify that the following details occur in the exchange between the Joiner,
# the Joiner_Router and the Commissioner
# 1. UDP port (Specified by the Commissioner: in Discovery Response) is used as destination port
# for UDP datagrams from Joiner_1 to the Commissioner.
pkts.range(_cpkts.index).filter_mle_cmd(MLE_DISCOVERY_RESPONSE).must_next().must_verify(
lambda p: {
NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_NAME_TLV, NM_STEERING_DATA_TLV, NM_COMMISSIONER_UDP_PORT_TLV,
NM_JOINER_UDP_PORT_TLV, NM_DISCOVERY_RESPONSE_TLV
} == set(p.thread_meshcop.tlv.type))
# 2. Joiner_1 sends an initial DTLS-ClientHello handshake record to the Commissioner
pkts.filter(lambda p: p.dtls.handshake.type == [HANDSHAKE_CLIENT_HELLO]).must_next()
# 3. The Joiner_Router receives the initial DTLS-ClientHello handshake record and sends a RLY_RX.ntf
# message to the Commissioner
# Todo: verify coap payload
jr_rloc16 = pv.vars["JOINER_ROUTER_RLOC16"]
c_rloc16 = pv.vars["COMMISSIONER_RLOC16"]
pkts.filter_coap_request(RLY_RX_URI).must_next().must_verify(
lambda p: p.wpan.src16 == jr_rloc16 and p.wpan.dst16 == c_rloc16)
# 4. The Commissioner receives the RLY_RX.ntf message and sends a RLY_TX.ntf message to the Joiner_Router
pkts.filter_coap_request(RLY_TX_URI).must_next().must_verify(
lambda p: p.wpan.src16 == c_rloc16 and p.wpan.dst16 == jr_rloc16)
if __name__ == '__main__':
@@ -30,6 +30,8 @@
import unittest
import thread_cert
from pktverify.consts import MLE_CHILD_ID_RESPONSE, MLE_DISCOVERY_RESPONSE, HANDSHAKE_CLIENT_HELLO, NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_NAME_TLV, NM_STEERING_DATA_TLV, NM_COMMISSIONER_UDP_PORT_TLV, NM_JOINER_UDP_PORT_TLV, NM_DISCOVERY_RESPONSE_TLV, RLY_RX_URI, RLY_TX_URI
from pktverify.packet_verifier import PacketVerifier
COMMISSIONER = 1
JOINER_ROUTER = 2
@@ -41,17 +43,20 @@ class Cert_8_2_02_JoinerRouter(thread_cert.TestCase):
TOPOLOGY = {
COMMISSIONER: {
'masterkey': 'deadbeefdeadbeefdeadbeefdeadbeef',
'name': 'COMMISSIONER',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rsdn',
'panid': 0xface,
'router_selection_jitter': 1
},
JOINER_ROUTER: {
'name': 'JOINER_ROUTER',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rsdn',
'router_selection_jitter': 1
},
JOINER: {
'name': 'JOINER',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rsdn',
'router_selection_jitter': 1
@@ -91,10 +96,40 @@ class Cert_8_2_02_JoinerRouter(thread_cert.TestCase):
self.nodes[JOINER].interface_up()
self.nodes[JOINER].joiner_start('20DKSP')
self.simulator.go(10)
self.assertNotEqual(
self.nodes[JOINER].get_masterkey(),
self.nodes[COMMISSIONER].get_masterkey(),
)
self.collect_rloc16s()
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
COMMISSIONER = pv.vars['COMMISSIONER']
_cpkts = pkts.filter_wpan_src64(COMMISSIONER)
_cpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
# Step 3: Verify that the following details occur in the exchange between the Joiner,
# the Joiner_Router and the Commissioner
# 1. UDP port (Specified by the Commissioner: in Discovery Response) is used as destination port
# for UDP datagrams from Joiner_1 to the Commissioner.
pkts.range(_cpkts.index).filter_mle_cmd(MLE_DISCOVERY_RESPONSE).must_next().must_verify(
lambda p: {
NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_NAME_TLV, NM_STEERING_DATA_TLV, NM_COMMISSIONER_UDP_PORT_TLV,
NM_JOINER_UDP_PORT_TLV, NM_DISCOVERY_RESPONSE_TLV
} == set(p.thread_meshcop.tlv.type))
# 2. Joiner_1 sends an initial DTLS-ClientHello handshake record to the Commissioner
pkts.filter(lambda p: p.dtls.handshake.type == [HANDSHAKE_CLIENT_HELLO]).must_next()
# 3. The Joiner_Router receives the initial DTLS-ClientHello handshake record and sends a RLY_RX.ntf
# message to the Commissioner
# Todo: verify coap payload
jr_rloc16 = pv.vars["JOINER_ROUTER_RLOC16"]
c_rloc16 = pv.vars["COMMISSIONER_RLOC16"]
pkts.filter_coap_request(RLY_RX_URI).must_next().must_verify(
lambda p: p.wpan.src16 == jr_rloc16 and p.wpan.dst16 == c_rloc16)
# 4. The Commissioner receives the RLY_RX.ntf message and sends a RLY_TX.ntf message to the Joiner_Router
pkts.filter_coap_request(RLY_TX_URI).must_next().must_verify(
lambda p: p.wpan.src16 == c_rloc16 and p.wpan.dst16 == jr_rloc16)
if __name__ == '__main__':
@@ -73,6 +73,8 @@ MLE_CHILD_ID_RESPONSE = 12
MLE_CHILD_UPDATE_REQUEST = 13
MLE_CHILD_UPDATE_RESPONSE = 14
MLE_ANNOUNCE = 15
MLE_DISCOVERY_REQUEST = 16
MLE_DISCOVERY_RESPONSE = 17
# COAP URIs
ADDR_QRY_URI = '/a/aq'
@@ -82,6 +84,8 @@ ADDR_SOL_URI = '/a/as'
ADDR_REL_URI = '/a/ar'
SVR_DATA_URI = '/a/sd'
ND_DATA_URI = '/a/nd'
RLY_RX_URI = '/c/rx'
RLY_TX_URI = '/c/tx'
# MLE TLVs
SOURCE_ADDRESS_TLV = 0
@@ -124,6 +128,38 @@ NL_ND_OPTION_TLV = 8
NL_ND_DATA_TLV = 9
NL_THREAD_NETWORK_DATA_TLV = 10
# MeshCop TLVs
NM_CHANNEL_TLV = 0
NM_PAN_ID_TLV = 1
NM_EXTENDED_PAN_ID_TLV = 2
NM_NETWORK_NAME_TLV = 3
NM_PSKC_TLV = 4
NM_NETWORK_MASTER_KEY_TLV = 5
NM_NETWORK_KEY_SEQUENCE_COUNTER_TLV = 6
NM_NETWORK_MESH_LOCAL_PREFIX_TLV = 7
NM_STEERING_DATA_TLV = 8
NM_SECURITY_POLICY_TLV = 12
NM_COMMISSIONER_UDP_PORT_TLV = 15
NM_JOINER_UDP_PORT_TLV = 18
NM_CHANNEL_MASK_TLV = 53
NM_DISCOVERY_RESPONSE_TLV = 129
# DTLS
HANDSHAKE_HELLO_REQUEST = 0
HANDSHAKE_CLIENT_HELLO = 1
HANDSHAKE_SERVER_HELLO = 2
HANDSHAKE_HELLO_VERIFY_REQUEST = 3
HANDSHAKE_CERTIFICATE = 11
HANDSHAKE_SERVER_KEY_EXCHANGE = 12
HANDSHAKE_CERTIFICATE_REQUEST = 13
HANDSHAKE_SERVER_HELLO_DONE = 14
HANDSHAKE_CERTIFICATE_VERIFY = 15
HANDSHAKE_CLIENT_KEY_EXCHANGE = 16
HANDSHAKE_FINISHED = 20
CONTENT_CHANGE_CIPHER_SPEC = 20
CONTENT_ALERT = 21
CONTENT_HANDSHAKE = 22
# DUA related constants
ADDRESS_QUERY_INITIAL_RETRY_DELAY = 15
@@ -148,6 +184,7 @@ INFINITE_COST_TIMEOUT = 90
REAL_LAYER_NAMES = {
'mle',
'coap',
'dtls',
'wpan',
'eth',
'tcp',
@@ -479,6 +479,12 @@ _LAYER_FIELDS = {
'coap.tlv.router_mask_assigned': _auto,
'coap.tlv.router_mask_id_seq': _auto,
# dtls
'dtls.handshake.type': _list(_auto),
'dtls.handshake.cookie': _auto,
'dtls.record.content_type': _list(_auto),
'dtls.alert_message.desc': _auto,
# thread_address
'thread_address.tlv.type': _list(_auto),
'thread_address.tlv.status': _auto,