1#!/usr/bin/env python3 2# 3# Copyright (c) 2024, 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 ipaddress 31import unittest 32import math 33 34import command 35import config 36import thread_cert 37 38# Test description: 39# 40# This test verifies key rotation and key guard time mechanisms. 41# 42# 43# Topology: 44# 45# leader --- router 46# | \ 47# | \ 48# child reed 49# 50 51LEADER = 1 52CHILD = 2 53REED = 3 54ROUTER = 4 55 56 57class MleMsgKeySeqJump(thread_cert.TestCase): 58 USE_MESSAGE_FACTORY = False 59 SUPPORT_NCP = False 60 61 TOPOLOGY = { 62 LEADER: { 63 'name': 'LEADER', 64 'mode': 'rdn', 65 }, 66 CHILD: { 67 'name': 'CHILD', 68 'is_mtd': True, 69 'mode': 'rn', 70 }, 71 REED: { 72 'name': 'REED', 73 'mode': 'rn' 74 }, 75 ROUTER: { 76 'name': 'ROUTER', 77 'mode': 'rdn', 78 }, 79 } 80 81 def test(self): 82 leader = self.nodes[LEADER] 83 child = self.nodes[CHILD] 84 reed = self.nodes[REED] 85 router = self.nodes[ROUTER] 86 87 nodes = [leader, child, reed, router] 88 89 #------------------------------------------------------------------- 90 # Form the network. 91 92 for node in nodes: 93 node.set_key_sequence_counter(0) 94 95 leader.start() 96 self.simulator.go(config.LEADER_STARTUP_DELAY) 97 self.assertEqual(leader.get_state(), 'leader') 98 99 child.start() 100 reed.start() 101 self.simulator.go(5) 102 self.assertEqual(child.get_state(), 'child') 103 self.assertEqual(reed.get_state(), 'child') 104 105 router.start() 106 self.simulator.go(config.ROUTER_STARTUP_DELAY) 107 self.assertEqual(router.get_state(), 'router') 108 109 #------------------------------------------------------------------- 110 # Validate the initial key seq counter and key switch guard time 111 112 for node in nodes: 113 self.assertEqual(node.get_key_sequence_counter(), 0) 114 self.assertEqual(node.get_key_switch_guardtime(), 624) 115 116 #------------------------------------------------------------------- 117 # Change the key rotation time a bunch of times and make sure that 118 # the key switch guard time is properly changed (should be set 119 # to 93% of the rotation time). 120 121 for rotation_time in [100, 1, 10, 888, 2]: 122 reed.start_dataset_updater(security_policy=[rotation_time, 'onrc']) 123 guardtime = math.floor(rotation_time * 93 / 100) if rotation_time >= 2 else 1 124 self.simulator.go(100) 125 for node in nodes: 126 self.assertEqual(node.get_key_switch_guardtime(), guardtime) 127 128 #------------------------------------------------------------------- 129 # Wait for key rotation time (2 hours) and check that all nodes 130 # moved to the next key seq counter 131 132 self.simulator.go(2 * 60 * 60) 133 for node in nodes: 134 self.assertEqual(node.get_key_sequence_counter(), 1) 135 136 #------------------------------------------------------------------- 137 # Manually increment the key sequence counter on leader and make 138 # sure other nodes are not updated due to key guard time. 139 140 router.set_key_sequence_counter(2) 141 142 self.simulator.go(50 * 60) 143 144 self.assertEqual(router.get_key_sequence_counter(), 2) 145 146 for node in [leader, reed, child]: 147 self.assertEqual(node.get_key_sequence_counter(), 1) 148 149 #------------------------------------------------------------------- 150 # Make sure nodes can communicate with each other. 151 152 self.assertTrue(leader.ping(router.get_mleid())) 153 self.assertTrue(router.ping(child.get_mleid())) 154 155 #------------------------------------------------------------------- 156 # Wait for rotation time to expire. Validate that the `router` 157 # has moved to key seq `3` and all other nodes also followed. 158 159 self.simulator.go(75 * 60) 160 161 self.assertEqual(router.get_key_sequence_counter(), 3) 162 163 for node in nodes: 164 self.assertEqual(node.get_key_sequence_counter(), 3) 165 166 self.assertTrue(leader.ping(router.get_mleid())) 167 self.assertTrue(router.ping(child.get_mleid())) 168 169 170if __name__ == '__main__': 171 unittest.main() 172