mirror of
https://github.com/espressif/openthread.git
synced 2026-09-09 02:30:11 +00:00
[tests] remove Cert_8_1, Cert_8_2, and Cert_8_3 thread-cert tests (#12659)
This commit removes several thread-cert Python tests that are now covered by the Nexus test framework. Nexus provides more efficient and reliable testing for these scenarios. The following tests are removed: - Cert_8_1_01_Commissioning.py - Cert_8_1_02_Commissioning.py - Cert_8_1_06_Commissioning.py - Cert_8_2_01_JoinerRouter.py - Cert_8_2_02_JoinerRouter.py - Cert_8_2_05_JoinerRouter.py - Cert_8_3_01_CommissionerPetition.py
This commit is contained in:
@@ -1,272 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2016, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
import unittest
|
||||
|
||||
import command
|
||||
import config
|
||||
import dtls
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_DISCOVERY_REQUEST, 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, CONTENT_APPLICATION_DATA, 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_REQUEST_TLV, NM_DISCOVERY_RESPONSE_TLV, THREAD_DISCOVERY_TLV, CONTENT_CHANGE_CIPHER_SPEC, CONTENT_HANDSHAKE, CONTENT_ALERT
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
COMMISSIONER = 1
|
||||
JOINER = 2
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify the DTLS sessions between the
|
||||
# on-mesh Commissioner and a Joiner when the correct PSKd is used
|
||||
#
|
||||
# Note that many of the messages/records exchanged are encrypted
|
||||
# and cannot be observe
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Commissioner
|
||||
# |
|
||||
# Joiner
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Commissioner
|
||||
# Joiner
|
||||
|
||||
|
||||
class Cert_8_1_01_Commissioning(thread_cert.TestCase):
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
COMMISSIONER: {
|
||||
'name': 'COMMISSIONER',
|
||||
'network_key': '00112233445566778899aabbccddeeff',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
JOINER: {
|
||||
'name': 'JOINER',
|
||||
'network_key': 'deadbeefdeadbeefdeadbeefdeadbeef',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[COMMISSIONER].interface_up()
|
||||
self.nodes[COMMISSIONER].thread_start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'leader')
|
||||
self.nodes[COMMISSIONER].commissioner_start()
|
||||
self.simulator.go(3)
|
||||
self.nodes[COMMISSIONER].commissioner_add_joiner(self.nodes[JOINER].get_eui64(), 'PSKD01')
|
||||
|
||||
self.nodes[JOINER].interface_up()
|
||||
self.nodes[JOINER].joiner_start('PSKD01')
|
||||
self.simulator.go(10)
|
||||
self.simulator.read_cert_messages_in_commissioning_log([COMMISSIONER, JOINER])
|
||||
self.assertEqual(
|
||||
self.nodes[JOINER].get_networkkey(),
|
||||
self.nodes[COMMISSIONER].get_networkkey(),
|
||||
)
|
||||
joiner_messages = self.simulator.get_messages_sent_by(JOINER)
|
||||
commissioner_messages = self.simulator.get_messages_sent_by(COMMISSIONER)
|
||||
|
||||
# 5.8,9,10,11
|
||||
# - Joiner
|
||||
command.check_joiner_commissioning_messages(joiner_messages.commissioning_messages)
|
||||
# - Commissioner
|
||||
command.check_commissioner_commissioning_messages(commissioner_messages.commissioning_messages)
|
||||
# As commissioner is also joiner router
|
||||
command.check_joiner_router_commissioning_messages(commissioner_messages.commissioning_messages)
|
||||
self.nodes[JOINER].thread_start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[JOINER].get_state(), 'router')
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
COMMISSIONER = pv.vars['COMMISSIONER']
|
||||
COMMISSIONER_VERSION = pv.vars['COMMISSIONER_VERSION']
|
||||
JOINER_VERSION = pv.vars['JOINER_VERSION']
|
||||
|
||||
# Step 3: Joiner sends MLE Discovery Request
|
||||
# MLE Discovery Request message MUST have these values:
|
||||
# - MLE Security Suite: 255 (No MLE Security)
|
||||
# - Thread Discovery TLV
|
||||
# Sub-TLVs:
|
||||
# - Discovery Request TLV
|
||||
# - Protocol Version: 2 or 3
|
||||
# (depends on the Thread stack version in testing)
|
||||
pkts.filter_mle_cmd(MLE_DISCOVERY_REQUEST).\
|
||||
filter_LLARMA().\
|
||||
filter(lambda p:
|
||||
[THREAD_DISCOVERY_TLV] == p.mle.tlv.type and\
|
||||
[NM_DISCOVERY_REQUEST_TLV] == p.thread_meshcop.tlv.type and\
|
||||
p.thread_meshcop.tlv.discovery_req_ver == JOINER_VERSION
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 4: Commissioner sends MLE Discovery Response
|
||||
# MLE Discovery Response message MUST have these values:
|
||||
# - MLE Security Suite: 255 (No MLE Security)
|
||||
# - Source Address in IEEE 802.15.4 header MUST be set to
|
||||
# the MAC Extended Address (64-bit)
|
||||
# - Destination Address in IEEE 802.15.4 header MUST be
|
||||
# set to Discovery Request Source Address
|
||||
# - Thread Discovery TLV
|
||||
# Sub-TLVs:
|
||||
# - Discovery Request TLV
|
||||
# - Protocol Version: 2 or 3
|
||||
# (depends on the Thread stack version in testing)
|
||||
# - Extended PAN ID TLV
|
||||
# - Joiner UDP Port TLV
|
||||
# - Network Name TLV
|
||||
# - Steering Data TLV
|
||||
# - Commissioner UDP Port TLV (optional)
|
||||
_rs_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter_mle_cmd(MLE_DISCOVERY_RESPONSE).\
|
||||
filter(lambda p: {
|
||||
NM_EXTENDED_PAN_ID_TLV,
|
||||
NM_NETWORK_NAME_TLV,
|
||||
NM_STEERING_DATA_TLV,
|
||||
NM_JOINER_UDP_PORT_TLV,
|
||||
NM_DISCOVERY_RESPONSE_TLV
|
||||
} <= set(p.thread_meshcop.tlv.type) and\
|
||||
p.thread_meshcop.tlv.discovery_rsp_ver == COMMISSIONER_VERSION
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 5: Verify the following details occur in the exchange between
|
||||
# Joiner and the Commissioner
|
||||
# 1. UDP port (Specified by the Commissioner: in Discovery Response)
|
||||
# is used as destination port for UDP datagrams from Joiner to
|
||||
# the Commissioner.
|
||||
|
||||
# 2. Joiner sends an initial DTLS-ClientHello handshake record to the
|
||||
# Commissioner
|
||||
pkts.filter_wpan_dst64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
p.dtls.handshake.type == [HANDSHAKE_CLIENT_HELLO] and\
|
||||
p.udp.srcport in _rs_pkt.thread_meshcop.tlv.udp_port and\
|
||||
p.udp.dstport in _rs_pkt.thread_meshcop.tlv.udp_port
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 3. The Commissioner receives the initial DTLS-ClientHello handshake
|
||||
# record and sends a DTLS-HelloVerifyRequest handshake record Joiner
|
||||
_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
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 receives the DTLS-HelloVerifyRequest handshake record and sends
|
||||
# a subsequent DTLS-ClientHello handshake record in one UDP datagram to the
|
||||
# Commissioner
|
||||
# Verify that both DTLS-HelloVerifyRequest and subsequent DTLS-ClientHello
|
||||
# contain the same cookie
|
||||
pkts.filter_wpan_dst64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
p.dtls.handshake.type == [HANDSHAKE_CLIENT_HELLO] and\
|
||||
p.dtls.handshake.cookie == _pkt.dtls.handshake.cookie
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 5. Commissioner must correctly receive the subsequent DTLSClientHello
|
||||
# handshake record and then send, in order, DTLSServerHello,
|
||||
# DTLS-ServerKeyExchange and DTLSServerHelloDone handshake records to Joiner
|
||||
pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
p.dtls.handshake.type == [HANDSHAKE_SERVER_HELLO,
|
||||
HANDSHAKE_SERVER_KEY_EXCHANGE,
|
||||
HANDSHAKE_SERVER_HELLO_DONE]
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 6. Joiner 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.
|
||||
pkts.filter_wpan_dst64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
p.dtls.handshake.type == [HANDSHAKE_CLIENT_KEY_EXCHANGE] and\
|
||||
{
|
||||
CONTENT_CHANGE_CIPHER_SPEC,
|
||||
CONTENT_HANDSHAKE
|
||||
} == set(p.dtls.record.content_type)
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 7. Commissioner receives the DTLS-ClientKeyExchange handshake record, the
|
||||
# DTLS-ChangeCipherSpec record and the encrypted DTLS-Finished handshake record,
|
||||
# and sends a DTLS-ChangeCipherSpec record and an encrypted DTLSFinished handshake
|
||||
# record in that order to Joiner
|
||||
pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter(lambda p: {
|
||||
CONTENT_CHANGE_CIPHER_SPEC,
|
||||
CONTENT_HANDSHAKE
|
||||
} == set(p.dtls.record.content_type)
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 8. Joiner receives the DTLS-ChangeCipherSpec record and the encrypted DTLS-Finished
|
||||
# handshake record and sends a JOIN_FIN.req message in an encrypted DTLS-ApplicationData
|
||||
# record in a single UDP datagram to Commissioner.
|
||||
pkts.filter_wpan_dst64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
[CONTENT_APPLICATION_DATA] == p.dtls.record.content_type
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 9. Commissioner receives the encrypted DTLS-ApplicationData record and sends a
|
||||
# JOIN_FIN.rsp message in an encrypted DTLS-ApplicationData record in a single
|
||||
# UDP datagram to Joiner
|
||||
pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
[CONTENT_APPLICATION_DATA] == p.dtls.record.content_type
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 10. Commissioner sends an encrypted JOIN_ENT.ntf message to Joiner
|
||||
|
||||
# 11. Joiner receives the encrypted JOIN_ENT.ntf message and sends an encrypted
|
||||
# JOIN_ENT.ntf dummy response to Commissioner
|
||||
|
||||
# Check Step 8 ~ 11 in test()
|
||||
|
||||
# 12. Joiner sends an encrypted DTLS-Alert record with a code of 0 (close_notify)
|
||||
# to Commissioner
|
||||
pkts.filter_wpan_dst64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
[CONTENT_ALERT] == p.dtls.record.content_type
|
||||
).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,116 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2016, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
import unittest
|
||||
|
||||
import config
|
||||
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
|
||||
|
||||
|
||||
class Cert_8_1_02_Commissioning(thread_cert.TestCase):
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
COMMISSIONER: {
|
||||
'name': 'COMMISSIONER',
|
||||
'network_key': '00112233445566778899aabbccddeeff',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
JOINER: {
|
||||
'name': 'JOINER',
|
||||
'network_key': 'deadbeefdeadbeefdeadbeefdeadbeef',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[COMMISSIONER].interface_up()
|
||||
self.nodes[COMMISSIONER].thread_start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'leader')
|
||||
self.nodes[COMMISSIONER].commissioner_start()
|
||||
self.simulator.go(3)
|
||||
self.nodes[COMMISSIONER].commissioner_add_joiner(self.nodes[JOINER].get_eui64(), 'PSKD01')
|
||||
|
||||
self.nodes[JOINER].interface_up()
|
||||
self.nodes[JOINER].joiner_start('10DKSP')
|
||||
self.simulator.go(10)
|
||||
|
||||
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__':
|
||||
unittest.main()
|
||||
@@ -1,240 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2020, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
import unittest
|
||||
|
||||
import command
|
||||
import config
|
||||
from mesh_cop import MeshCopState
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_DISCOVERY_REQUEST, 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, CONTENT_APPLICATION_DATA, 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_REQUEST_TLV, NM_DISCOVERY_RESPONSE_TLV, THREAD_DISCOVERY_TLV, CONTENT_CHANGE_CIPHER_SPEC, CONTENT_HANDSHAKE, CONTENT_ALERT
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
COMMISSIONER = 1
|
||||
JOINER = 2
|
||||
PSKD = 'PSKD01'
|
||||
URL_1 = 'www.openthread.org'
|
||||
URL_2 = 'www.wrongurl.org'
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify the DTLS session between an on-mesh
|
||||
# Commissioner and a Joiner and ensure that the session does not stay open.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Commissioner
|
||||
# |
|
||||
# Joiner
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Commissioner
|
||||
# Joiner
|
||||
|
||||
|
||||
class Cert_8_1_06_Commissioning(thread_cert.TestCase):
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
COMMISSIONER: {
|
||||
'name': 'COMMISSIONER',
|
||||
'network_key': '00112233445566778899aabbccddeeff',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
JOINER: {
|
||||
'network_key': 'deadbeefdeadbeefdeadbeefdeadbeef',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[COMMISSIONER].interface_up()
|
||||
self.nodes[COMMISSIONER].thread_start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'leader')
|
||||
self.nodes[COMMISSIONER].commissioner_set_provisioning_url(URL_1)
|
||||
self.nodes[COMMISSIONER].commissioner_start()
|
||||
self.simulator.go(3)
|
||||
self.nodes[COMMISSIONER].commissioner_add_joiner(self.nodes[JOINER].get_eui64(), PSKD)
|
||||
|
||||
self.nodes[JOINER].interface_up()
|
||||
self.nodes[JOINER].joiner_start(PSKD, URL_2)
|
||||
self.simulator.go(10)
|
||||
self.simulator.read_cert_messages_in_commissioning_log([COMMISSIONER, JOINER])
|
||||
self.assertEqual(
|
||||
self.nodes[JOINER].get_networkkey(),
|
||||
self.nodes[COMMISSIONER].get_networkkey(),
|
||||
)
|
||||
joiner_messages = self.simulator.get_messages_sent_by(JOINER)
|
||||
commissioner_messages = self.simulator.get_messages_sent_by(COMMISSIONER)
|
||||
|
||||
# 3.7, 8, 9, 10
|
||||
# - Joiner
|
||||
command.check_joiner_commissioning_messages(joiner_messages.commissioning_messages, URL_2)
|
||||
# - Commissioner
|
||||
command.check_commissioner_commissioning_messages(commissioner_messages.commissioning_messages,
|
||||
MeshCopState.REJECT)
|
||||
# As commissioner is also joiner router
|
||||
command.check_joiner_router_commissioning_messages(commissioner_messages.commissioning_messages)
|
||||
self.nodes[JOINER].thread_start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[JOINER].get_state(), 'router')
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
COMMISSIONER = pv.vars['COMMISSIONER']
|
||||
COMMISSIONER_VERSION = pv.vars['COMMISSIONER_VERSION']
|
||||
|
||||
_rs_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter_mle_cmd(MLE_DISCOVERY_RESPONSE).\
|
||||
filter(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) and\
|
||||
p.thread_meshcop.tlv.discovery_rsp_ver ==
|
||||
COMMISSIONER_VERSION
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 3: Verify the following details occur in the exchange between
|
||||
# Joiner and the Commissioner
|
||||
# 1. UDP port (Specified by the Commissioner: in Discovery Response)
|
||||
# is used as destination port for UDP datagrams from Joiner to
|
||||
# the Commissioner.
|
||||
|
||||
# 2. Joiner_1 sends an initial DTLS-ClientHello handshake record to the
|
||||
# Commissioner
|
||||
pkts.filter_wpan_dst64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
p.dtls.handshake.type == [HANDSHAKE_CLIENT_HELLO] and\
|
||||
p.udp.srcport in _rs_pkt.thread_meshcop.tlv.udp_port and\
|
||||
p.udp.dstport in _rs_pkt.thread_meshcop.tlv.udp_port
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 3. The Commissioner receives the initial DTLS-ClientHello handshake
|
||||
# record and sends a DTLS-HelloVerifyRequest handshake record Joiner
|
||||
_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
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 receives the DTLS-HelloVerifyRequest handshake record and sends
|
||||
# a subsequent DTLS-ClientHello handshake record in one UDP datagram to the
|
||||
# Commissioner
|
||||
# Verify that both DTLS-HelloVerifyRequest and subsequent DTLS-ClientHello
|
||||
# contain the same cookie
|
||||
pkts.filter_wpan_dst64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
p.dtls.handshake.type == [HANDSHAKE_CLIENT_HELLO] and\
|
||||
p.dtls.handshake.cookie == _pkt.dtls.handshake.cookie
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 5. Commissioner receives the subsequent DTLSClientHello handshake record
|
||||
# and then send, in order, DTLSServerHello, DTLS-ServerKeyExchange and
|
||||
# DTLSServerHelloDone handshake records to Joiner
|
||||
pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
p.dtls.handshake.type == [HANDSHAKE_SERVER_HELLO,
|
||||
HANDSHAKE_SERVER_KEY_EXCHANGE,
|
||||
HANDSHAKE_SERVER_HELLO_DONE]
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 6. Joiner 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.
|
||||
pkts.filter_wpan_dst64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
p.dtls.handshake.type == [HANDSHAKE_CLIENT_KEY_EXCHANGE] and\
|
||||
{
|
||||
CONTENT_CHANGE_CIPHER_SPEC,
|
||||
CONTENT_HANDSHAKE
|
||||
} == set(p.dtls.record.content_type)
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 7. Commissioner receives the DTLS-ClientKeyExchange handshake record, the
|
||||
# DTLS-ChangeCipherSpec record and the encrypted DTLS-Finished handshake record,
|
||||
# and sends a DTLS-ChangeCipherSpec record and an encrypted DTLSFinished handshake
|
||||
# record in that order to Joiner
|
||||
pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter(lambda p: {
|
||||
CONTENT_CHANGE_CIPHER_SPEC,
|
||||
CONTENT_HANDSHAKE
|
||||
} == set(p.dtls.record.content_type)
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 8. Joiner receives the DTLS-ChangeCipherSpec record and the encrypted DTLS-Finished
|
||||
# handshake record and sends a JOIN_FIN.req message in an encrypted DTLS-ApplicationData
|
||||
# record in a single UDP datagram to Commissioner.
|
||||
pkts.filter_wpan_dst64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
[CONTENT_APPLICATION_DATA] == p.dtls.record.content_type
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 9. Commissioner receives the encrypted DTLS-ApplicationData record and sends a
|
||||
# JOIN_FIN.rsp message in an encrypted DTLS-ApplicationData record in a single
|
||||
# UDP datagram to Joiner
|
||||
# The JOIN_FIN.req message must contain a Provisioning URL TLV which the
|
||||
# Commissioner will not recognize.
|
||||
pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
[CONTENT_APPLICATION_DATA] == p.dtls.record.content_type
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 10. Joiner receives the encrypted JOIN_ENT.ntf message and sends an encrypted
|
||||
# JOIN_ENT.ntf with Reject state to Commissioner
|
||||
|
||||
# Verify Step 7 - 10 in test()
|
||||
|
||||
# 11. Joiner sends an encrypted DTLS-Alert record with a code of 0 (close_notify)
|
||||
# to Commissioner
|
||||
pkts.filter_wpan_dst64(COMMISSIONER).\
|
||||
filter(lambda p:
|
||||
[CONTENT_ALERT] == p.dtls.record.content_type
|
||||
).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,141 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2016, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
import unittest
|
||||
|
||||
import config
|
||||
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
|
||||
JOINER = 3
|
||||
|
||||
|
||||
class Cert_8_2_01_JoinerRouter(thread_cert.TestCase):
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
COMMISSIONER: {
|
||||
'name': 'COMMISSIONER',
|
||||
'network_key': '00112233445566778899aabbccddeeff',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
JOINER_ROUTER: {
|
||||
'name': 'JOINER_ROUTER',
|
||||
'network_key': 'deadbeefdeadbeefdeadbeefdeadbeef',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
JOINER: {
|
||||
'name': 'JOINER',
|
||||
'network_key': 'deadbeefdeadbeefdeadbeefdeadbeef',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[COMMISSIONER].interface_up()
|
||||
self.nodes[COMMISSIONER].thread_start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'leader')
|
||||
|
||||
self.nodes[COMMISSIONER].commissioner_start()
|
||||
self.simulator.go(5)
|
||||
self.nodes[COMMISSIONER].commissioner_add_joiner(self.nodes[JOINER_ROUTER].get_eui64(), 'PSKD01')
|
||||
self.nodes[COMMISSIONER].commissioner_add_joiner(self.nodes[JOINER].get_eui64(), 'PSKD02')
|
||||
self.simulator.go(5)
|
||||
|
||||
self.nodes[JOINER_ROUTER].interface_up()
|
||||
self.nodes[JOINER_ROUTER].joiner_start('PSKD01')
|
||||
self.simulator.go(10)
|
||||
self.assertEqual(
|
||||
self.nodes[JOINER_ROUTER].get_networkkey(),
|
||||
self.nodes[COMMISSIONER].get_networkkey(),
|
||||
)
|
||||
|
||||
self.nodes[JOINER_ROUTER].thread_start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[JOINER_ROUTER].get_state(), 'router')
|
||||
|
||||
self.nodes[COMMISSIONER].enable_allowlist()
|
||||
self.nodes[COMMISSIONER].add_allowlist(self.nodes[JOINER_ROUTER].get_addr64())
|
||||
|
||||
self.nodes[JOINER].enable_allowlist()
|
||||
self.nodes[JOINER].add_allowlist(self.nodes[JOINER_ROUTER].get_addr64())
|
||||
|
||||
self.nodes[JOINER].interface_up()
|
||||
self.nodes[JOINER].joiner_start('PSKD02')
|
||||
self.simulator.go(10)
|
||||
self.assertEqual(
|
||||
self.nodes[JOINER].get_networkkey(),
|
||||
self.nodes[COMMISSIONER].get_networkkey(),
|
||||
)
|
||||
|
||||
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__':
|
||||
unittest.main()
|
||||
@@ -1,133 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2016, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
import unittest
|
||||
|
||||
import config
|
||||
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
|
||||
JOINER = 3
|
||||
|
||||
|
||||
class Cert_8_2_02_JoinerRouter(thread_cert.TestCase):
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
COMMISSIONER: {
|
||||
'name': 'COMMISSIONER',
|
||||
'network_key': '00112233445566778899aabbccddeeff',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
JOINER_ROUTER: {
|
||||
'name': 'JOINER_ROUTER',
|
||||
'network_key': 'deadbeefdeadbeefdeadbeefdeadbeef',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
JOINER: {
|
||||
'name': 'JOINER',
|
||||
'network_key': 'deadbeefdeadbeefdeadbeefdeadbeef',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[COMMISSIONER].interface_up()
|
||||
self.nodes[COMMISSIONER].thread_start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'leader')
|
||||
|
||||
self.nodes[COMMISSIONER].commissioner_start()
|
||||
self.simulator.go(5)
|
||||
self.nodes[COMMISSIONER].commissioner_add_joiner(self.nodes[JOINER_ROUTER].get_eui64(), 'PSKD01')
|
||||
self.nodes[COMMISSIONER].commissioner_add_joiner(self.nodes[JOINER].get_eui64(), 'PSKD02')
|
||||
self.simulator.go(5)
|
||||
|
||||
self.nodes[JOINER_ROUTER].interface_up()
|
||||
self.nodes[JOINER_ROUTER].joiner_start('PSKD01')
|
||||
self.simulator.go(10)
|
||||
self.assertEqual(
|
||||
self.nodes[JOINER_ROUTER].get_networkkey(),
|
||||
self.nodes[COMMISSIONER].get_networkkey(),
|
||||
)
|
||||
|
||||
self.nodes[JOINER_ROUTER].thread_start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[JOINER_ROUTER].get_state(), 'router')
|
||||
|
||||
self.nodes[COMMISSIONER].enable_allowlist()
|
||||
self.nodes[COMMISSIONER].add_allowlist(self.nodes[JOINER_ROUTER].get_addr64())
|
||||
|
||||
self.nodes[JOINER].enable_allowlist()
|
||||
self.nodes[JOINER].add_allowlist(self.nodes[JOINER_ROUTER].get_addr64())
|
||||
|
||||
self.nodes[JOINER].interface_up()
|
||||
self.nodes[JOINER].joiner_start('20DKSP')
|
||||
self.simulator.go(10)
|
||||
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__':
|
||||
unittest.main()
|
||||
@@ -1,234 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2020, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
import unittest
|
||||
|
||||
import command
|
||||
import config
|
||||
from mesh_cop import MeshCopState
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_CHILD_ID_RESPONSE, MLE_DISCOVERY_RESPONSE, HANDSHAKE_CLIENT_HELLO, HANDSHAKE_HELLO_VERIFY_REQUEST, HANDSHAKE_SERVER_HELLO, HANDSHAKE_SERVER_KEY_EXCHANGE, HANDSHAKE_SERVER_HELLO_DONE, HANDSHAKE_CLIENT_KEY_EXCHANGE, CONTENT_CHANGE_CIPHER_SPEC, CONTENT_HANDSHAKE, CONTENT_APPLICATION_DATA, 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, NM_JOINER_DTLS_ENCAPSULATION_TLV, NM_JOINER_UDP_PORT_TLV, NM_JOINER_IID_TLV, NM_JOINER_ROUTER_LOCATOR_TLV, NM_JOINER_ROUTER_KEK_TLV, RLY_RX_URI, RLY_TX_URI
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
COMMISSIONER = 1
|
||||
JOINER_ROUTER = 2
|
||||
JOINER = 3
|
||||
PSKD = 'PSKD01'
|
||||
URL_1 = 'www.openthread.org'
|
||||
URL_2 = 'www.wrongurl.org'
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify that the DUT sends and receives
|
||||
# relayed DTLS traffic correctly, when the wrong commissioning application is
|
||||
# requested by the Joiner.
|
||||
# It also verifies that the DUT (as a Joiner Router) sends JOIN_ENT.ntf encrypted
|
||||
# with KEK.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Commissioner
|
||||
# |
|
||||
# Joiner Router
|
||||
# |
|
||||
# Joiner
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Commissioner
|
||||
# Joiner Router
|
||||
|
||||
|
||||
class Cert_8_2_05_JoinerRouter(thread_cert.TestCase):
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
COMMISSIONER: {
|
||||
'name': 'COMMISSIONER',
|
||||
'network_key': '00112233445566778899aabbccddeeff',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
JOINER_ROUTER: {
|
||||
'name': 'JOINER_ROUTER',
|
||||
'network_key': 'deadbeefdeadbeefdeadbeefdeadbeef',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
JOINER: {
|
||||
'name': 'JOINER',
|
||||
'network_key': 'deadbeefdeadbeefdeadbeefdeadbeef',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[COMMISSIONER].interface_up()
|
||||
self.nodes[COMMISSIONER].thread_start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'leader')
|
||||
|
||||
self.nodes[COMMISSIONER].commissioner_set_provisioning_url(URL_1)
|
||||
self.nodes[COMMISSIONER].commissioner_start()
|
||||
self.simulator.go(5)
|
||||
self.nodes[COMMISSIONER].commissioner_add_joiner(self.nodes[JOINER_ROUTER].get_eui64(), PSKD)
|
||||
self.nodes[COMMISSIONER].commissioner_add_joiner(self.nodes[JOINER].get_eui64(), PSKD)
|
||||
self.simulator.go(5)
|
||||
|
||||
self.nodes[JOINER_ROUTER].interface_up()
|
||||
self.nodes[JOINER_ROUTER].joiner_start(PSKD, URL_1)
|
||||
self.simulator.go(10)
|
||||
self.assertEqual(
|
||||
self.nodes[JOINER_ROUTER].get_networkkey(),
|
||||
self.nodes[COMMISSIONER].get_networkkey(),
|
||||
)
|
||||
|
||||
self.nodes[JOINER_ROUTER].thread_start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[JOINER_ROUTER].get_state(), 'router')
|
||||
|
||||
self.nodes[COMMISSIONER].enable_allowlist()
|
||||
self.nodes[COMMISSIONER].add_allowlist(self.nodes[JOINER_ROUTER].get_addr64())
|
||||
|
||||
self.nodes[JOINER].enable_allowlist()
|
||||
self.nodes[JOINER].add_allowlist(self.nodes[JOINER_ROUTER].get_addr64())
|
||||
|
||||
self.nodes[JOINER].interface_up()
|
||||
self.nodes[JOINER].joiner_start(PSKD, URL_2)
|
||||
self.simulator.go(10)
|
||||
|
||||
self.simulator.read_cert_messages_in_commissioning_log([COMMISSIONER, JOINER_ROUTER])
|
||||
commissioner_messages = self.simulator.get_messages_sent_by(COMMISSIONER)
|
||||
|
||||
self.assertEqual(
|
||||
self.nodes[JOINER].get_networkkey(),
|
||||
self.nodes[COMMISSIONER].get_networkkey(),
|
||||
)
|
||||
# check commissioner sends JOIN_FIN.rsp with reject
|
||||
command.check_commissioner_commissioning_messages(commissioner_messages.commissioning_messages,
|
||||
MeshCopState.REJECT)
|
||||
self.collect_rloc16s()
|
||||
self.collect_ipaddrs()
|
||||
|
||||
self.nodes[JOINER].thread_start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[JOINER].get_state(), 'router')
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
COMMISSIONER = pv.vars['COMMISSIONER']
|
||||
JOINER_ROUTER_RLOC16 = pv.vars["JOINER_ROUTER_RLOC16"]
|
||||
COMMISSIONER_RLOC16 = pv.vars["COMMISSIONER_RLOC16"]
|
||||
JOINER_ROUTER_LLA = pv.vars["JOINER_ROUTER_LLA"]
|
||||
|
||||
# verify Joiner Router attaches to Commissioner
|
||||
pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter_ipv6_dst(JOINER_ROUTER_LLA).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
|
||||
must_next()
|
||||
|
||||
_rs_pkt = pkts.filter_mle_cmd(MLE_DISCOVERY_RESPONSE).\
|
||||
filter(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)
|
||||
).\
|
||||
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 Commissioner in Discovery Response) is used as
|
||||
# destination port for UDP datagrams from Joiner to Commissioner.
|
||||
|
||||
# 2. Joiner sends an initial DTLS-ClientHello handshake record to the
|
||||
# Joiner Router
|
||||
_ch_pkt = pkts.filter_ipv6_dst(JOINER_ROUTER_LLA).\
|
||||
filter(lambda p:
|
||||
p.dtls.handshake.type == [HANDSHAKE_CLIENT_HELLO] and\
|
||||
p.udp.srcport in _rs_pkt.thread_meshcop.tlv.udp_port and\
|
||||
p.udp.dstport in _rs_pkt.thread_meshcop.tlv.udp_port
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 3. The Joiner_Router receives the initial DTLS-ClientHello handshake record and
|
||||
# sends a RLY_RX.ntf message to the Commissioner containing:
|
||||
# CoAP URI-Path
|
||||
# NON POST coap://<C>/c/rx
|
||||
# CoAP Payload
|
||||
# Joiner DTLS Encapsulation TLV
|
||||
# Joiner UDP Port TLV
|
||||
# Joiner IID TLV
|
||||
# Joiner_Router Locator TLV
|
||||
_pkt = pkts.filter_coap_request(RLY_RX_URI).\
|
||||
filter_wpan_src16(JOINER_ROUTER_RLOC16).\
|
||||
filter_wpan_dst16(COMMISSIONER_RLOC16).\
|
||||
filter(lambda p: {
|
||||
NM_JOINER_DTLS_ENCAPSULATION_TLV,
|
||||
NM_JOINER_UDP_PORT_TLV,
|
||||
NM_JOINER_IID_TLV,
|
||||
NM_JOINER_ROUTER_LOCATOR_TLV
|
||||
} <= set(p.thread_meshcop.tlv.type) and\
|
||||
p.thread_meshcop.tlv.udp_port == [_ch_pkt.udp.dstport] and\
|
||||
p.thread_meshcop.tlv.jr_locator == JOINER_ROUTER_RLOC16
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# 4. The Commissioner receives the RLY_RX.ntf message and sends a RLY_TX.ntf message to
|
||||
# the Joiner_Router containing:
|
||||
# CoAP URI-Path
|
||||
# NON POST coap://<JR>/c/tx
|
||||
# CoAP Payload
|
||||
# Joiner DTLS Encapsulation TLV
|
||||
# Joiner UDP Port TLV
|
||||
# Joiner IID TLV
|
||||
# Joiner_Router Locator TLV
|
||||
# Joiner_Router KEK TLV
|
||||
pkts.filter_coap_request(RLY_TX_URI).\
|
||||
filter_wpan_src16(COMMISSIONER_RLOC16).\
|
||||
filter_wpan_dst16(JOINER_ROUTER_RLOC16).\
|
||||
filter(lambda p: {
|
||||
NM_JOINER_DTLS_ENCAPSULATION_TLV,
|
||||
NM_JOINER_UDP_PORT_TLV,
|
||||
NM_JOINER_IID_TLV,
|
||||
NM_JOINER_ROUTER_LOCATOR_TLV,
|
||||
NM_JOINER_ROUTER_KEK_TLV
|
||||
} <= set(p.thread_meshcop.tlv.type) and\
|
||||
p.thread_meshcop.tlv.udp_port == [_ch_pkt.udp.dstport] and\
|
||||
p.thread_meshcop.tlv.jr_locator == JOINER_ROUTER_RLOC16
|
||||
).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,368 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2020, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
import unittest
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_DATA_RESPONSE, LEAD_PET_URI, LEAD_KA_URI, MGMT_COMMISSIONER_SET_URI, NM_COMMISSIONER_ID_TLV, NM_COMMISSIONER_SESSION_ID_TLV, NM_STATE_TLV, NM_STEERING_DATA_TLV, NM_BORDER_AGENT_LOCATOR_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, SOURCE_ADDRESS_TLV, NWD_COMMISSIONING_DATA_TLV, MESHCOP_ACCEPT, MESHCOP_REJECT
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
LEADER = 1
|
||||
COMMISSIONER = 2
|
||||
FAKE_JOINER = '166e0a0000000999'
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify that a Commissioner Candidate is able
|
||||
# to register itself to the network as a Commissioner, send periodic Commissioner
|
||||
# keep-alive messages, update steering data and unregister itself as a Commissioner
|
||||
# Leader accepts the Commissioner Candidate as a Commissioner in the network, responds
|
||||
# to periodic Commissioner keep-alive messages, propagates Thread Network Data correctly
|
||||
# in the network and unregisters the Commissioner on its request
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Commissioner
|
||||
# |
|
||||
# Leader
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Leader
|
||||
# Commissioner
|
||||
|
||||
|
||||
class Cert_8_3_01_CommissionerPetition(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'network_key': '00112233445566778899aabbccddeeff',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
COMMISSIONER: {
|
||||
'name': 'COMMISSIONER',
|
||||
'network_key': '00112233445566778899aabbccddeeff',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
self.nodes[COMMISSIONER].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
|
||||
|
||||
self.collect_rlocs()
|
||||
self.collect_rloc16s()
|
||||
self.collect_leader_aloc(LEADER)
|
||||
|
||||
self.nodes[COMMISSIONER].commissioner_start()
|
||||
self.simulator.go(60)
|
||||
|
||||
self.nodes[COMMISSIONER].commissioner_add_joiner(FAKE_JOINER, 'PSKD01')
|
||||
self.simulator.go(5)
|
||||
|
||||
self.nodes[COMMISSIONER].commissioner_stop()
|
||||
self.simulator.go(5)
|
||||
self.nodes[COMMISSIONER].commissioner_start()
|
||||
self.simulator.go(5)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_ALOC = pv.vars['LEADER_ALOC']
|
||||
LEADER_RLOC = pv.vars['LEADER_RLOC']
|
||||
LEADER_RLOC16 = pv.vars['LEADER_RLOC16']
|
||||
COMMISSIONER = pv.vars['COMMISSIONER']
|
||||
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
|
||||
|
||||
# Step 2: Commissioner sends a petition request (LEAD_PET.req) to Leader:
|
||||
# CoAP Request URI
|
||||
# CON POST coap://<L>:MM/c/lp
|
||||
# CoAP Payload
|
||||
# Commissioner ID TLV
|
||||
pv.verify_attached('COMMISSIONER', 'LEADER')
|
||||
_pkt = pkts.last()
|
||||
_leader_pet_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter_wpan_dst16(LEADER_RLOC16).\
|
||||
filter_coap_request(LEAD_PET_URI).\
|
||||
filter(lambda p: {
|
||||
NM_COMMISSIONER_ID_TLV
|
||||
} <= set(p.coap.tlv.type)\
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 3: Leader accepts Commissioner to the network, sends a Leader Petition
|
||||
# Response (LEAD_PET.rsp) to Commissioner:
|
||||
# CoAP Response Code
|
||||
# 2.04 Changed
|
||||
# CoAP Payload
|
||||
# State TLV (value = Accept)
|
||||
# Commissioner ID TLV
|
||||
# Commissioner Session ID TLV
|
||||
#
|
||||
# Leader sends a MLE Data Response to the network with the
|
||||
# following TLVs:
|
||||
# - Active Timestamp TLV
|
||||
# - Leader Data TLV
|
||||
# - Network Data TLV
|
||||
# - Source Address TLV
|
||||
pkts.filter_ipv6_src_dst(_leader_pet_pkt.ipv6.dst, COMMISSIONER_RLOC).\
|
||||
filter_coap_ack(LEAD_PET_URI).\
|
||||
filter(lambda p: {
|
||||
NM_STATE_TLV,
|
||||
NM_COMMISSIONER_ID_TLV,
|
||||
NM_COMMISSIONER_SESSION_ID_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_meshcop.tlv.state == MESHCOP_ACCEPT
|
||||
).\
|
||||
must_next()
|
||||
_dr_pkt = pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_DATA_RESPONSE).\
|
||||
filter(lambda p: {
|
||||
NETWORK_DATA_TLV,
|
||||
SOURCE_ADDRESS_TLV,
|
||||
ACTIVE_TIMESTAMP_TLV,
|
||||
LEADER_DATA_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
{
|
||||
NWD_COMMISSIONING_DATA_TLV
|
||||
} <= set(p.thread_nwd.tlv.type) and\
|
||||
{
|
||||
NM_BORDER_AGENT_LOCATOR_TLV,
|
||||
NM_COMMISSIONER_SESSION_ID_TLV,
|
||||
NM_STEERING_DATA_TLV
|
||||
} <= set(p.thread_meshcop.tlv.type) and\
|
||||
p.mle.tlv.leader_data.data_version ==
|
||||
(_pkt.mle.tlv.leader_data.data_version + 1) % 256 and\
|
||||
p.thread_nwd.tlv.stable == [0]
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 4: Commissioner sends a commissioner keep-alive request (LEAD_KA.req) to Leader:
|
||||
# CoAP Request URI
|
||||
# CON POST coap://<L>:MM/c/la
|
||||
# CoAP Payload
|
||||
# State TLV (value = Accept)
|
||||
# Commissioner Session ID TLV
|
||||
_leader_ka_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
|
||||
filter_coap_request(LEAD_KA_URI).\
|
||||
filter(lambda p: {
|
||||
NM_STATE_TLV,
|
||||
NM_COMMISSIONER_SESSION_ID_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_meshcop.tlv.state == MESHCOP_ACCEPT
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 5: Leader sends a commissioner keep-alive response (LEAD_KA.rsp) to Commissioner:
|
||||
# CoAP Response Code
|
||||
# 2.04 Changed
|
||||
# CoAP Payload
|
||||
# State TLV (value = Accept)
|
||||
pkts.filter_ipv6_src_dst(_leader_ka_pkt.ipv6.dst, COMMISSIONER_RLOC).\
|
||||
filter_coap_ack(LEAD_KA_URI).\
|
||||
filter(lambda p: {
|
||||
NM_STATE_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_meshcop.tlv.state == MESHCOP_ACCEPT
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 6: Commissioner sends a Set Commissioner Dataset Request (MGMT_COMMISSIONER_SET.req)
|
||||
# to Leader ALOC 0xFC00 or Leader RLOC:
|
||||
# CoAP Request URI
|
||||
# CON POST coap://<L>:MM/c/cs
|
||||
# CoAP Payload
|
||||
# Commissioner Session ID TLV
|
||||
# Steering Data TLV
|
||||
_mgmt_set_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
|
||||
filter_coap_request(MGMT_COMMISSIONER_SET_URI).\
|
||||
filter(lambda p: {
|
||||
NM_STEERING_DATA_TLV,
|
||||
NM_COMMISSIONER_SESSION_ID_TLV
|
||||
} <= set(p.coap.tlv.type)
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 7: Leader sends a Set Commissioner Dataset Response (MGMT_COMMISSIONER_SET.rsp) to
|
||||
# Commissioner:
|
||||
# CoAP Response Code
|
||||
# 2.04 Changed
|
||||
# CoAP Payload
|
||||
# State TLV (value = Accept)
|
||||
#
|
||||
# Leader sends a MLE Data Response to the network with the
|
||||
# following TLVs:
|
||||
# - Active Timestamp TLV
|
||||
# - Leader Data TLV
|
||||
# - Network Data TLV
|
||||
# - Source Address TLV
|
||||
pkts.filter_ipv6_src_dst(_mgmt_set_pkt.ipv6.dst, COMMISSIONER_RLOC).\
|
||||
filter_coap_ack(MGMT_COMMISSIONER_SET_URI).\
|
||||
filter(lambda p: {
|
||||
NM_STATE_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_meshcop.tlv.state == MESHCOP_ACCEPT
|
||||
).\
|
||||
must_next()
|
||||
|
||||
_dr_pkt2 = pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_DATA_RESPONSE).\
|
||||
filter(lambda p: {
|
||||
NETWORK_DATA_TLV,
|
||||
SOURCE_ADDRESS_TLV,
|
||||
ACTIVE_TIMESTAMP_TLV,
|
||||
LEADER_DATA_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
{
|
||||
NWD_COMMISSIONING_DATA_TLV
|
||||
} <= set(p.thread_nwd.tlv.type) and\
|
||||
{
|
||||
NM_BORDER_AGENT_LOCATOR_TLV,
|
||||
NM_COMMISSIONER_SESSION_ID_TLV,
|
||||
NM_STEERING_DATA_TLV
|
||||
} <= set(p.thread_meshcop.tlv.type) and\
|
||||
p.mle.tlv.leader_data.data_version ==
|
||||
(_dr_pkt.mle.tlv.leader_data.data_version + 1) % 256 and\
|
||||
p.thread_nwd.tlv.stable == [0]
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 8: Commissioner sends a resign request via commissioner keep-alive request
|
||||
# (LEAD_KA.req) to Leader:
|
||||
# CoAP Request URI
|
||||
# CON POST coap://<L>:MM/c/la
|
||||
# CoAP Payload
|
||||
# State TLV (value = Reject)
|
||||
# Commissioner Session ID TLV
|
||||
_leader_ka_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
|
||||
filter_coap_request(LEAD_KA_URI).\
|
||||
filter(lambda p: {
|
||||
NM_STATE_TLV,
|
||||
NM_COMMISSIONER_SESSION_ID_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_meshcop.tlv.state == MESHCOP_REJECT
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 9: Leader accepts the resignation by responding with ‘Reject’ in a commissioner keep-alive
|
||||
# response (LEAD_KA.rsp) to Commissioner:
|
||||
# CoAP Response Code
|
||||
# 2.04 Changed
|
||||
# CoAP Payload
|
||||
# State TLV (value = Reject)
|
||||
#
|
||||
# Leader sends a MLE Data Response to the network with the
|
||||
# following TLVs:
|
||||
# - Active Timestamp TLV
|
||||
# - Leader Data TLV
|
||||
# - Network Data TLV
|
||||
# - Source Address TLV
|
||||
pkts.filter_ipv6_src_dst(_leader_ka_pkt.ipv6.dst, COMMISSIONER_RLOC).\
|
||||
filter_coap_ack(LEAD_KA_URI).\
|
||||
filter(lambda p: {
|
||||
NM_STATE_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_meshcop.tlv.state == MESHCOP_REJECT
|
||||
).\
|
||||
must_next()
|
||||
_dr_pkt3 = pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_DATA_RESPONSE).\
|
||||
filter(lambda p: {
|
||||
NETWORK_DATA_TLV,
|
||||
SOURCE_ADDRESS_TLV,
|
||||
ACTIVE_TIMESTAMP_TLV,
|
||||
LEADER_DATA_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
{
|
||||
NWD_COMMISSIONING_DATA_TLV
|
||||
} <= set(p.thread_nwd.tlv.type) and\
|
||||
{
|
||||
NM_COMMISSIONER_SESSION_ID_TLV
|
||||
} <= set(p.thread_meshcop.tlv.type) and\
|
||||
(p.mle.tlv.leader_data.data_version -
|
||||
_dr_pkt2.mle.tlv.leader_data.data_version) % 256 <= 127 and\
|
||||
p.thread_nwd.tlv.stable == [0]
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 10: Commissioner sends a petition request (LEAD_PET.req) to Leader:
|
||||
# CoAP Request URI
|
||||
# CON POST coap://<L>:MM/c/lp
|
||||
# CoAP Payload
|
||||
# Commissioner ID TLV
|
||||
_leader_pet_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
|
||||
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
|
||||
filter_coap_request(LEAD_PET_URI).\
|
||||
filter(lambda p: {
|
||||
NM_COMMISSIONER_ID_TLV
|
||||
} <= set(p.coap.tlv.type)\
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 11: Leader accepts Commissioner to the network, sends a Leader Petition
|
||||
# Response (LEAD_PET.rsp) to Commissioner:
|
||||
# CoAP Response Code
|
||||
# 2.04 Changed
|
||||
# CoAP Payload
|
||||
# State TLV (value = Accept)
|
||||
# Commissioner ID TLV
|
||||
# Commissioner Session ID TLV (contains higher Session ID number
|
||||
# than in Step 9)
|
||||
pkts.filter_ipv6_src_dst(_leader_pet_pkt.ipv6.dst, COMMISSIONER_RLOC).\
|
||||
filter_coap_ack(LEAD_PET_URI).\
|
||||
filter(lambda p: {
|
||||
NM_STATE_TLV,
|
||||
NM_COMMISSIONER_ID_TLV,
|
||||
NM_COMMISSIONER_SESSION_ID_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_meshcop.tlv.state == MESHCOP_ACCEPT and\
|
||||
p.thread_meshcop.tlv.commissioner_sess_id ==
|
||||
(_dr_pkt3.thread_meshcop.tlv.commissioner_sess_id + 1) % 65536
|
||||
).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user