1#!/usr/bin/env python3 2# 3# Copyright (c) 2020, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29 30import unittest 31 32from mesh_cop import TlvType 33import config 34import thread_cert 35from pktverify.consts import MLE_DATA_RESPONSE, MGMT_ACTIVE_SET_URI, MGMT_ACTIVE_GET_URI, LEADER_ALOC, NM_COMMISSIONER_SESSION_ID_TLV, NM_ACTIVE_TIMESTAMP_TLV, NM_SECURITY_POLICY_TLV, NM_NETWORK_KEY_TLV, MLE_DISCOVERY_RESPONSE 36from pktverify.packet_verifier import PacketVerifier 37from pktverify.layer_fields import nullField 38from pktverify.bytes import Bytes 39 40LEADER = 1 41COMMISSIONER_1 = 2 42COMMISSIONER_2 = 3 43THREAD_NODE = 4 44 45# Test Purpose and Description: 46# ----------------------------- 47# The purpose of this test case is to verify network behavior when Security 48# Policy TLV “O”,”N”,”R”,”B” bits are disabled. “C” bit is not tested as it 49# requires an External Commissioner which is currently not part of Thread 50# Certification. 51# 52# Notes: Due to the packet parsing compatible issue for supporting Thread 1.2 53# and 1.1, the security policy values can be fetched only in the unknown 54# field. 55# 56# Test Topology: 57# ------------- 58# Leader ---- Commissioner_2 59# Thread_Node | 60# Commissioner_1 61# 62# Notes: Commissioner_2 is introduced in Step 10 and powoff 63# Thread_Node sends scan beacon 64# 65# DUT Types: 66# ---------- 67# Leader 68 69 70class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase): 71 SUPPORT_NCP = False 72 USE_MESSAGE_FACTORY = False 73 74 TOPOLOGY = { 75 LEADER: { 76 'name': 'LEADER', 77 'active_dataset': { 78 'timestamp': 1, 79 'channel': 19, 80 'network_key': '00112233445566778899aabbccddeeff', 81 'security_policy': [3600, 'onrc'] 82 }, 83 'mode': 'rdn', 84 }, 85 COMMISSIONER_1: { 86 'name': 'COMMISSIONER_1', 87 'active_dataset': { 88 'timestamp': 1, 89 'channel': 19, 90 'network_key': '00112233445566778899aabbccddeeff', 91 'security_policy': [3600, 'onrc'] 92 }, 93 'mode': 'rdn', 94 'allowlist': [LEADER] 95 }, 96 COMMISSIONER_2: { 97 'name': 'COMMISSIONER_2', 98 'mode': 'rdn', 99 'allowlist': [LEADER] 100 }, 101 THREAD_NODE: { 102 'name': 'THREAD_NODE', 103 'active_dataset': { 104 'timestamp': 1, 105 'channel': 19, 106 'network_key': '00112233445566778899aabbccddeeff', 107 'security_policy': [3600, 'onrc'] 108 }, 109 'mode': 'rdn', 110 }, 111 } 112 113 def test(self): 114 self.nodes[LEADER].start() 115 self.simulator.go(config.LEADER_STARTUP_DELAY) 116 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 117 118 self.nodes[COMMISSIONER_1].start() 119 self.simulator.go(config.ROUTER_STARTUP_DELAY) 120 self.assertEqual(self.nodes[COMMISSIONER_1].get_state(), 'router') 121 122 self.nodes[COMMISSIONER_1].commissioner_start() 123 self.simulator.go(5) 124 self.nodes[COMMISSIONER_1].commissioner_add_joiner('*', 'PSKD01') 125 126 self.collect_rlocs() 127 leader_rloc = self.nodes[LEADER].get_rloc() 128 129 # Step 2 130 self.nodes[COMMISSIONER_1].send_mgmt_active_get() 131 self.simulator.go(5) 132 133 # Step 5 134 # Disabling O-Bit security_policy = [3600, 0b01110000] 135 self.nodes[COMMISSIONER_1].send_mgmt_active_set( 136 active_timestamp=15, 137 security_policy=[3600, 'nrc'], 138 ) 139 self.simulator.go(5) 140 141 # Step 7 142 # Get NetworkKey 143 self.nodes[COMMISSIONER_1].send_mgmt_active_get(leader_rloc, [TlvType.NETWORK_KEY]) 144 self.simulator.go(5) 145 146 # Step 9 147 # Disabling N-Bit security_policy = [3600, 0b10110000] 148 self.nodes[COMMISSIONER_1].send_mgmt_active_set( 149 active_timestamp=20, 150 security_policy=[3600, 'orc'], 151 ) 152 self.simulator.go(5) 153 154 # Step 10 155 # Add Native Commissioner 156 self.nodes[COMMISSIONER_2].interface_up() 157 self.nodes[COMMISSIONER_2].joiner_start('10DKSP') 158 self.simulator.go(5) 159 self.nodes[COMMISSIONER_2].reset() 160 161 # Step 13 162 # Disabling B-Bit security_policy = [3600, 0b11110000] 163 self.nodes[COMMISSIONER_1].send_mgmt_active_set( 164 active_timestamp=25, 165 security_policy=[3600, 'onrc'], 166 ) 167 self.simulator.go(5) 168 169 # Step 15 170 # send beacons 171 self.nodes[THREAD_NODE].start() 172 self.simulator.go(2) 173 self.nodes[THREAD_NODE].scan(result=0) 174 self.simulator.go(20) 175 176 # Step 17 177 # Disabling R-Bit security_policy = [3600, 0b11010000] 178 self.nodes[COMMISSIONER_1].send_mgmt_active_set( 179 active_timestamp=30, 180 security_policy=[3600, 'onc'], 181 ) 182 self.simulator.go(5) 183 184 def verify(self, pv): 185 pkts = pv.pkts 186 pv.summary.show() 187 188 LEADER = pv.vars['LEADER'] 189 LEADER_RLOC = pv.vars['LEADER_RLOC'] 190 COMMISSIONER_1 = pv.vars['COMMISSIONER_1'] 191 COMMISSIONER_1_RLOC = pv.vars['COMMISSIONER_1_RLOC'] 192 COMMISSIONER_2 = pv.vars['COMMISSIONER_2'] 193 194 # Step 1: Ensure the topology is formed correctly 195 pv.verify_attached('COMMISSIONER_1', 'LEADER') 196 197 # Step 2: Commissioner_1 sends MGMT_ACTIVE_GET.req to Leader 198 # CoAP Request URI 199 # coap://[<L>]:MM/c/ag 200 # CoAP Payload 201 # <empty> 202 pkts.filter_wpan_src64(COMMISSIONER_1).\ 203 filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC).\ 204 filter_coap_request(MGMT_ACTIVE_GET_URI).\ 205 filter(lambda p: p.thread_meshcop.tlv.type is nullField).\ 206 must_next() 207 208 # Step 3: Leader MUST send MGMT_ACTIVE_GET.rsp to the Commissioner_1 209 # CoAP Response Code 210 # 2.04 Changed 211 # CoAP Payload 212 # Security Policy TLV 213 # Bits “O”,”N”,”R”,”C” should be set to 1 214 pkts.filter_wpan_src64(LEADER).\ 215 filter_ipv6_dst(COMMISSIONER_1_RLOC).\ 216 filter_coap_ack(MGMT_ACTIVE_GET_URI).\ 217 filter(lambda p: (p.thread_meshcop.tlv.sec_policy_rot == 3600 and 218 p.thread_meshcop.tlv.sec_policy_o == 1 and 219 p.thread_meshcop.tlv.sec_policy_n == 1 and 220 p.thread_meshcop.tlv.sec_policy_r == 1 and 221 p.thread_meshcop.tlv.sec_policy_c == 1) or 222 (p.thread_meshcop.tlv.unknown == '0e10f7')).\ 223 must_next() 224 225 # Step 5: Commissioner_1 sends MGMT_ACTIVE_SET.req to Leader 226 # CoAP Request URI 227 # coap://[<L>]:MM/c/as 228 # CoAP Payload 229 # Commissioner Session ID TLV 230 # Active Timestamp TLV > stored value in step 4 231 # Security Policy TLV with “O” bit disabled 232 pkts.filter_wpan_src64(COMMISSIONER_1). \ 233 filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC). \ 234 filter_coap_request(MGMT_ACTIVE_SET_URI). \ 235 filter(lambda p: { 236 NM_COMMISSIONER_SESSION_ID_TLV, 237 NM_ACTIVE_TIMESTAMP_TLV, 238 NM_SECURITY_POLICY_TLV 239 } <= set(p.thread_meshcop.tlv.type) and\ 240 p.thread_meshcop.tlv.active_tstamp == 15 and\ 241 (p.thread_meshcop.tlv.sec_policy_o == 0 or 242 p.thread_meshcop.tlv.unknown == '0e1077')).\ 243 must_next() 244 245 # Step 6: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1 246 # CoAP Response Code 247 # 2.04 Changed 248 # CoAP Payload 249 # State TLV (value = Accept (0x01)) 250 pkts.filter_wpan_src64(LEADER).\ 251 filter_ipv6_dst(COMMISSIONER_1_RLOC).\ 252 filter_coap_ack(MGMT_ACTIVE_SET_URI).\ 253 filter(lambda p: p.thread_meshcop.tlv.state == 1).\ 254 must_next() 255 256 # Step 7: Commissioner_1 sends MGMT_ACTIVE_GET.req to Leader 257 # CoAP Request URI 258 # coap://[<L>]:MM/c/ag 259 # CoAP Payload 260 # Network Key TLV 261 pkts.filter_wpan_src64(COMMISSIONER_1).\ 262 filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC).\ 263 filter_coap_request(MGMT_ACTIVE_GET_URI).\ 264 filter(lambda p: NM_NETWORK_KEY_TLV in p.thread_meshcop.tlv.type).\ 265 must_next() 266 267 # Step 8: Leader MUST send MGMT_ACTIVE_GET.rsp to the Commissioner_1 268 # CoAP Response Code 269 # 2.04 Changed 270 # CoAP Payload 271 # Network Key TLV MUST NOT be included 272 pkts.filter_wpan_src64(LEADER).\ 273 filter_ipv6_dst(COMMISSIONER_1_RLOC).\ 274 filter_coap_ack(MGMT_ACTIVE_GET_URI).\ 275 filter(lambda p: p.thread_meshcop.tlv.type is nullField).\ 276 must_next() 277 278 # Step 9: Commissioner_1 sends MGMT_ACTIVE_SET.req to Leader 279 # CoAP Request URI 280 # coap://[<L>]:MM/c/as 281 # CoAP Payload 282 # Commissioner Session ID TLV 283 # Active Timestamp TLV > stored value in step 5 284 # Security Policy TLV with “N” bit disabled 285 pkts.filter_wpan_src64(COMMISSIONER_1). \ 286 filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC). \ 287 filter_coap_request(MGMT_ACTIVE_SET_URI). \ 288 filter(lambda p: { 289 NM_COMMISSIONER_SESSION_ID_TLV, 290 NM_ACTIVE_TIMESTAMP_TLV, 291 NM_SECURITY_POLICY_TLV 292 } <= set(p.thread_meshcop.tlv.type) and\ 293 p.thread_meshcop.tlv.active_tstamp == 20 and\ 294 (p.thread_meshcop.tlv.sec_policy_n == 0 or 295 p.thread_meshcop.tlv.unknown == '0e10b7')).\ 296 must_next() 297 298 # Step 10: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1 299 # CoAP Response Code 300 # 2.04 Changed 301 # CoAP Payload 302 # State TLV (value = Accept (0x01)) 303 pkts.filter_wpan_src64(LEADER).\ 304 filter_ipv6_dst(COMMISSIONER_1_RLOC).\ 305 filter_coap_ack(MGMT_ACTIVE_SET_URI).\ 306 filter(lambda p: p.thread_meshcop.tlv.state == 1).\ 307 must_next() 308 309 # Step 12: Leader MUST send a Discovery Response with Native Commissioning 310 # bit set to “Not Allowed” 311 pkts.filter_wpan_src64(LEADER).\ 312 filter_mle_cmd(MLE_DISCOVERY_RESPONSE).\ 313 filter(lambda p: p.thread_meshcop.tlv.discovery_rsp_n == 0).\ 314 must_next() 315 316 # Step 13: Commissioner_1 sends MGMT_ACTIVE_SET.req to Leader 317 # CoAP Request URI 318 # coap://[<L>]:MM/c/as 319 # CoAP Payload 320 # Commissioner Session ID TLV 321 # Active Timestamp TLV > stored value in step 9 322 # Security Policy TLV with “B” bit disabled 323 pkts.filter_wpan_src64(COMMISSIONER_1). \ 324 filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC). \ 325 filter_coap_request(MGMT_ACTIVE_SET_URI). \ 326 filter(lambda p: { 327 NM_COMMISSIONER_SESSION_ID_TLV, 328 NM_ACTIVE_TIMESTAMP_TLV, 329 NM_SECURITY_POLICY_TLV 330 } <= set(p.thread_meshcop.tlv.type) and\ 331 p.thread_meshcop.tlv.active_tstamp == 25 and\ 332 (p.thread_meshcop.tlv.sec_policy_b == 0 or 333 p.thread_meshcop.tlv.unknown == '0e10f7')).\ 334 must_next() 335 336 # Step 14: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1 337 # CoAP Response Code 338 # 2.04 Changed 339 # CoAP Payload 340 # State TLV (value = Accept (0x01)) 341 pkts.filter_wpan_src64(LEADER).\ 342 filter_ipv6_dst(COMMISSIONER_1_RLOC).\ 343 filter_coap_ack(MGMT_ACTIVE_SET_URI).\ 344 filter(lambda p: p.thread_meshcop.tlv.state == 1).\ 345 must_next() 346 347 # Step 16: The DUT MUST send beacon response frames.The beacon payload MUST 348 # either be empty OR the payload format MUST be different from the 349 # Thread Beacon payload The Protocol ID and Version field values 350 # MUST be different from the values specified for the Thread beacon 351 # (Protocol ID= 3, Version = 2) 352 pkts.filter_wpan_src64(LEADER).\ 353 filter_wpan_beacon().\ 354 filter(lambda p: 355 (p.thread_bcn.protocol is nullField or\ 356 p.thread_bcn.protocol != 3) and\ 357 (p.thread_bcn.version is nullField or\ 358 p.thread_bcn.version != 2) 359 ).\ 360 must_next() 361 362 # Step 17: Commissioner_1 sends MGMT_ACTIVE_SET.req to Leader 363 # CoAP Request URI 364 # coap://[<L>]:MM/c/as 365 # CoAP Payload 366 # Commissioner Session ID TLV 367 # Active Timestamp TLV > stored value in step 9 368 # Security Policy TLV with “R” bit disabled 369 pkts.filter_wpan_src64(COMMISSIONER_1). \ 370 filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC). \ 371 filter_coap_request(MGMT_ACTIVE_SET_URI). \ 372 filter(lambda p: { 373 NM_COMMISSIONER_SESSION_ID_TLV, 374 NM_ACTIVE_TIMESTAMP_TLV, 375 NM_SECURITY_POLICY_TLV 376 } <= set(p.thread_meshcop.tlv.type) and\ 377 p.thread_meshcop.tlv.active_tstamp == 30 and\ 378 (p.thread_meshcop.tlv.sec_policy_r == 0 or 379 p.thread_meshcop.tlv.unknown == '0e10d7')).\ 380 must_next() 381 382 # Step 18: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1 383 # CoAP Response Code 384 # 2.04 Changed 385 # CoAP Payload 386 # State TLV (value = Accept (0x01)) 387 # Leader MUST multicast MLE Data Response to the Link-Local All Nodes 388 # multicast address (FF02::1) with active timestamp value as set in 389 # Step 17. 390 pkts.filter_wpan_src64(LEADER).\ 391 filter_ipv6_dst(COMMISSIONER_1_RLOC).\ 392 filter_coap_ack(MGMT_ACTIVE_SET_URI).\ 393 filter(lambda p: p.thread_meshcop.tlv.state == 1).\ 394 must_next() 395 pkts.filter_wpan_src64(LEADER).\ 396 filter_LLANMA().\ 397 filter_mle_cmd(MLE_DATA_RESPONSE).\ 398 filter(lambda p: p.mle.tlv.active_tstamp == 30).\ 399 must_next() 400 401 # Step 20: The DUT MUST send a unicast MLE Data Response to Commissioner_1. 402 # The Active Operational Set MUST contain a Security Policy TLV with 403 # R bit set to 0. 404 pkts.filter_wpan_src64(LEADER).\ 405 filter_wpan_dst64(COMMISSIONER_1). \ 406 filter_mle_cmd(MLE_DATA_RESPONSE).\ 407 filter(lambda p: 408 p.mle.tlv.active_tstamp == 30 and\ 409 (p.thread_meshcop.tlv.sec_policy_r == 0 or 410 p.thread_meshcop.tlv.unknown == '0e10d7')).\ 411 must_next() 412 413 414if __name__ == '__main__': 415 unittest.main() 416