diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index e48bcdfe7..96754e234 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -42,6 +42,7 @@ #include "common/logging.hpp" #include "common/string.hpp" #include "crypto/pbkdf2_cmac.h" +#include "meshcop/joiner.hpp" #include "meshcop/joiner_router.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" @@ -285,7 +286,7 @@ otError Commissioner::AddJoiner(const Mac::ExtAddress *aEui64, const char *aPskd VerifyOrExit(mState == OT_COMMISSIONER_STATE_ACTIVE, error = OT_ERROR_INVALID_STATE); - VerifyOrExit(StringLength(aPskd, Dtls::kPskMaxLength + 1) <= Dtls::kPskMaxLength, error = OT_ERROR_INVALID_ARGS); + VerifyOrExit(MeshCoP::Joiner::IsPskdValid(aPskd), error = OT_ERROR_INVALID_ARGS); IgnoreError(RemoveJoiner(aEui64, 0, kJoinerOpFlagNotNotifyLeader)); // remove immediately diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index dad7e3b96..a927e5d91 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -41,6 +41,7 @@ #include "common/instance.hpp" #include "common/locator-getters.hpp" #include "common/logging.hpp" +#include "common/string.hpp" #include "meshcop/meshcop.hpp" #include "radio/radio.hpp" #include "thread/thread_netif.hpp" @@ -86,6 +87,30 @@ exit: return; } +bool Joiner::IsPskdValid(const char *aPskd) +{ + bool valid = false; + size_t pskdLength = StringLength(aPskd, kPskdMaxLength + 1); + + OT_STATIC_ASSERT(static_cast(kPskdMaxLength) <= static_cast(Dtls::kPskMaxLength), + "The maximum length of DTLS PSK is smaller than joiner PSKd"); + + VerifyOrExit(pskdLength >= kPskdMinLength && pskdLength <= kPskdMaxLength, OT_NOOP); + + for (size_t i = 0; i < pskdLength; i++) + { + char c = aPskd[i]; + + VerifyOrExit(isdigit(c) || isupper(c), OT_NOOP); + VerifyOrExit(c != 'I' && c != 'O' && c != 'Q' && c != 'Z', OT_NOOP); + } + + valid = true; + +exit: + return valid; +} + otError Joiner::Start(const char * aPskd, const char * aProvisioningUrl, const char * aVendorName, @@ -102,6 +127,8 @@ otError Joiner::Start(const char * aPskd, VerifyOrExit(mState == OT_JOINER_STATE_IDLE, error = OT_ERROR_BUSY); + VerifyOrExit(IsPskdValid(aPskd), error = OT_ERROR_INVALID_ARGS); + // Use random-generated extended address. randomAddress.GenerateRandom(); Get().SetExtAddress(randomAddress); diff --git a/src/core/meshcop/joiner.hpp b/src/core/meshcop/joiner.hpp index 168edb9a0..fc12eff63 100644 --- a/src/core/meshcop/joiner.hpp +++ b/src/core/meshcop/joiner.hpp @@ -109,12 +109,29 @@ public: */ void GetJoinerId(Mac::ExtAddress &aJoinerId) const; + /** + * This method validates the PSKd. + * + * Per Thread specification, a Joining Device Credential is encoded as + * uppercase alphanumeric characters (base32-thread: 0-9, A-Z excluding + * I, O, Q, and Z for readability) with a minimum length of 6 such + * characters and a maximum length of 32 such characters. + * + * param[in] aPskd The PSKd to validate. + * + * @retval A boolean indicates whether the given @p aPskd is valid. + * + */ + static bool IsPskdValid(const char *aPskd); + private: enum { kJoinerUdpPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT, kConfigExtAddressDelay = 100, ///< [milliseconds] kReponseTimeout = 4000, ///< Maximum wait time to receive response [milliseconds]. + kPskdMinLength = 6, ///< Minimum PSKd length. + kPskdMaxLength = 32, ///< Maximum PSKd Length. }; struct JoinerRouter diff --git a/tests/scripts/thread-cert/Cert_8_1_01_Commissioning.py b/tests/scripts/thread-cert/Cert_8_1_01_Commissioning.py index 0bf673f02..7c3416479 100755 --- a/tests/scripts/thread-cert/Cert_8_1_01_Commissioning.py +++ b/tests/scripts/thread-cert/Cert_8_1_01_Commissioning.py @@ -62,10 +62,10 @@ class Cert_8_1_01_Commissioning(thread_cert.TestCase): self.nodes[COMMISSIONER].commissioner_start() self.simulator.go(3) self.nodes[COMMISSIONER].commissioner_add_joiner( - self.nodes[JOINER].get_eui64(), 'OPENTHREAD') + self.nodes[JOINER].get_eui64(), 'PSKD01') self.nodes[JOINER].interface_up() - self.nodes[JOINER].joiner_start('OPENTHREAD') + self.nodes[JOINER].joiner_start('PSKD01') self.simulator.go(10) self.simulator.read_cert_messages_in_commissioning_log( [COMMISSIONER, JOINER]) diff --git a/tests/scripts/thread-cert/Cert_8_1_02_Commissioning.py b/tests/scripts/thread-cert/Cert_8_1_02_Commissioning.py index 382bdd441..3c3357cdf 100755 --- a/tests/scripts/thread-cert/Cert_8_1_02_Commissioning.py +++ b/tests/scripts/thread-cert/Cert_8_1_02_Commissioning.py @@ -57,10 +57,10 @@ class Cert_8_1_02_Commissioning(thread_cert.TestCase): self.nodes[COMMISSIONER].commissioner_start() self.simulator.go(3) self.nodes[COMMISSIONER].commissioner_add_joiner( - self.nodes[JOINER].get_eui64(), 'OPENTHREAD') + self.nodes[JOINER].get_eui64(), 'PSKD01') self.nodes[JOINER].interface_up() - self.nodes[JOINER].joiner_start('DAERHTNEPO') + self.nodes[JOINER].joiner_start('10DKSP') self.simulator.go(10) self.assertNotEqual( self.nodes[JOINER].get_masterkey(), diff --git a/tests/scripts/thread-cert/Cert_8_2_01_JoinerRouter.py b/tests/scripts/thread-cert/Cert_8_2_01_JoinerRouter.py index 2691fa186..491545060 100755 --- a/tests/scripts/thread-cert/Cert_8_2_01_JoinerRouter.py +++ b/tests/scripts/thread-cert/Cert_8_2_01_JoinerRouter.py @@ -65,9 +65,9 @@ class Cert_8_2_01_JoinerRouter(thread_cert.TestCase): self.nodes[COMMISSIONER].commissioner_start() self.simulator.go(5) self.nodes[COMMISSIONER].commissioner_add_joiner( - self.nodes[JOINER_ROUTER].get_eui64(), 'OPENTHREAD') + self.nodes[JOINER_ROUTER].get_eui64(), 'PSKD01') self.nodes[COMMISSIONER].commissioner_add_joiner( - self.nodes[JOINER].get_eui64(), 'OPENTHREAD2') + self.nodes[JOINER].get_eui64(), 'PSKD02') self.simulator.go(5) self.nodes[COMMISSIONER].add_whitelist( @@ -76,7 +76,7 @@ class Cert_8_2_01_JoinerRouter(thread_cert.TestCase): self.nodes[COMMISSIONER].get_addr64()) self.nodes[JOINER_ROUTER].interface_up() - self.nodes[JOINER_ROUTER].joiner_start('OPENTHREAD') + self.nodes[JOINER_ROUTER].joiner_start('PSKD01') self.simulator.go(10) self.assertEqual( self.nodes[JOINER_ROUTER].get_masterkey(), @@ -95,7 +95,7 @@ class Cert_8_2_01_JoinerRouter(thread_cert.TestCase): self.nodes[JOINER].add_whitelist(self.nodes[JOINER_ROUTER].get_addr64()) self.nodes[JOINER].interface_up() - self.nodes[JOINER].joiner_start('OPENTHREAD2') + self.nodes[JOINER].joiner_start('PSKD02') self.simulator.go(10) self.assertEqual( self.nodes[JOINER].get_masterkey(), diff --git a/tests/scripts/thread-cert/Cert_8_2_02_JoinerRouter.py b/tests/scripts/thread-cert/Cert_8_2_02_JoinerRouter.py index f35c9811b..ab0a6e917 100755 --- a/tests/scripts/thread-cert/Cert_8_2_02_JoinerRouter.py +++ b/tests/scripts/thread-cert/Cert_8_2_02_JoinerRouter.py @@ -65,9 +65,9 @@ class Cert_8_2_02_JoinerRouter(thread_cert.TestCase): self.nodes[COMMISSIONER].commissioner_start() self.simulator.go(5) self.nodes[COMMISSIONER].commissioner_add_joiner( - self.nodes[JOINER_ROUTER].get_eui64(), 'OPENTHREAD') + self.nodes[JOINER_ROUTER].get_eui64(), 'PSKD01') self.nodes[COMMISSIONER].commissioner_add_joiner( - self.nodes[JOINER].get_eui64(), 'OPENTHREAD2') + self.nodes[JOINER].get_eui64(), 'PSKD02') self.simulator.go(5) self.nodes[COMMISSIONER].add_whitelist( @@ -76,7 +76,7 @@ class Cert_8_2_02_JoinerRouter(thread_cert.TestCase): self.nodes[COMMISSIONER].get_addr64()) self.nodes[JOINER_ROUTER].interface_up() - self.nodes[JOINER_ROUTER].joiner_start('OPENTHREAD') + self.nodes[JOINER_ROUTER].joiner_start('PSKD01') self.simulator.go(10) self.assertEqual( self.nodes[JOINER_ROUTER].get_masterkey(), @@ -95,7 +95,7 @@ class Cert_8_2_02_JoinerRouter(thread_cert.TestCase): self.nodes[JOINER].add_whitelist(self.nodes[JOINER_ROUTER].get_addr64()) self.nodes[JOINER].interface_up() - self.nodes[JOINER].joiner_start('2DAERHTNEPO') + self.nodes[JOINER].joiner_start('20DKSP') self.simulator.go(10) self.assertNotEqual( self.nodes[JOINER].get_masterkey(), diff --git a/tools/harness-thci/OpenThread.py b/tools/harness-thci/OpenThread.py index 404356877..d38838415 100644 --- a/tools/harness-thci/OpenThread.py +++ b/tools/harness-thci/OpenThread.py @@ -2035,7 +2035,7 @@ class OpenThread(IThci): def diagnosticQuery(self, strDestinationAddr, listTLV_ids=[]): self.diagnosticGet(strDestinationAddr, listTLV_ids) - def startNativeCommissioner(self, strPSKc='GRLpassWord'): + def startNativeCommissioner(self, strPSKc='GRLPASSPHRASE'): # TODO: Support the whole Native Commissioner functionality # Currently it only aims to trigger a Discovery Request message to pass # Certification test 5.8.4 @@ -2069,7 +2069,7 @@ class OpenThread(IThci): def setJoinKey(self, strPSKc): pass - def scanJoiner(self, xEUI='*', strPSKd='threadjpaketest'): + def scanJoiner(self, xEUI='*', strPSKd='THREADJPAKETEST'): """scan Joiner Args: @@ -2143,7 +2143,7 @@ class OpenThread(IThci): ModuleHelper.writeintodebuglogger('allowcommission() error: ' + str(e)) - def joinCommissioned(self, strPSKd='threadjpaketest', waitTime=20): + def joinCommissioned(self, strPSKd='THREADJPAKETEST', waitTime=20): """start joiner Args: diff --git a/tools/harness-thci/OpenThread_WpanCtl.py b/tools/harness-thci/OpenThread_WpanCtl.py index e12c5cc5d..4ae4b4bd3 100644 --- a/tools/harness-thci/OpenThread_WpanCtl.py +++ b/tools/harness-thci/OpenThread_WpanCtl.py @@ -2117,7 +2117,7 @@ class OpenThread_WpanCtl(IThci): def diagnosticReset(self, strDestinationAddr, listTLV_ids=[]): """@todo : required if as reference device""" - def startNativeCommissioner(self, strPSKc='GRLpassWord'): + def startNativeCommissioner(self, strPSKc='GRLPASSPHRASE'): # TODO: Support the whole Native Commissioner functionality # Currently it only aims to trigger a Discovery Request message to pass # Certification test 5.8.4 @@ -2152,7 +2152,7 @@ class OpenThread_WpanCtl(IThci): def setJoinKey(self, strPSKc): pass - def scanJoiner(self, xEUI='*', strPSKd='threadjpaketest'): + def scanJoiner(self, xEUI='*', strPSKd='THREADJPAKETEST'): """scan Joiner Args: @@ -2225,7 +2225,7 @@ class OpenThread_WpanCtl(IThci): ModuleHelper.WriteIntoDebugLogger('allowcommission() error: ' + str(e)) - def joinCommissioned(self, strPSKd='threadjpaketest', waitTime=20): + def joinCommissioned(self, strPSKd='THREADJPAKETEST', waitTime=20): """start joiner Args: