diff --git a/configure.ac b/configure.ac index eb9d6d0a1..c5c246230 100644 --- a/configure.ac +++ b/configure.ac @@ -433,6 +433,85 @@ MBEDTLS_CPPFLAGS="${MBEDTLS_CPPFLAGS} -I\${abs_top_srcdir}/third_party/mbedtls/r MBEDTLS_CPPFLAGS="${MBEDTLS_CPPFLAGS} -I\${abs_top_srcdir}/third_party/mbedtls/repo/include/mbedtls" MBEDTLS_CPPFLAGS="${MBEDTLS_CPPFLAGS} -DMBEDTLS_CONFIG_FILE=\\\"mbedtls-config.h\\\"" +# +# Thread Commissioner +# + +AC_ARG_ENABLE(commissioner, + [AS_HELP_STRING([--enable-commissioner],[Enable commissioner suport @<:@default=no@:>@.])], + [ + case "${enableval}" in + + no|yes) + enable_commissioner=${enableval} + ;; + + *) + AC_MSG_ERROR([Invalid value ${enable_commissioner} for --enable-commissioner]) + ;; + esac + ], + [enable_commissioner=no]) + +if test "$enable_commissioner" = "yes"; then + OPENTHREAD_ENABLE_COMMISSIONER=1 +else + OPENTHREAD_ENABLE_COMMISSIONER=0 +fi + +AC_MSG_RESULT(${enable_commissioner}) +AC_SUBST(OPENTHREAD_ENABLE_COMMISSIONER) +AM_CONDITIONAL([OPENTHREAD_ENABLE_COMMISSIONER], [test "${enable_commissioner}" = "yes"]) +AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_COMMISSIONER],[${OPENTHREAD_ENABLE_COMMISSIONER}],[Define to 1 to enable the commissioner role.]) + +# +# Thread Joiner +# + +AC_ARG_ENABLE(joiner, + [AS_HELP_STRING([--enable-joiner],[Enable joiner suport @<:@default=no@:>@.])], + [ + case "${enableval}" in + + no|yes) + enable_joiner=${enableval} + ;; + + *) + AC_MSG_ERROR([Invalid value ${enable_joiner} for --enable-joiner]) + ;; + esac + ], + [enable_joiner=no]) + +if test "$enable_joiner" = "yes"; then + OPENTHREAD_ENABLE_JOINER=1 +else + OPENTHREAD_ENABLE_JOINER=0 +fi + +AC_MSG_RESULT(${enable_joiner}) +AC_SUBST(OPENTHREAD_ENABLE_JOINER) +AM_CONDITIONAL([OPENTHREAD_ENABLE_JOINER], [test "${enable_joiner}" = "yes"]) +AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_JOINER],[${OPENTHREAD_ENABLE_JOINER}],[Define to 1 to enable the joiner role.]) + +if test "${enable_commissioner}" = "yes" -o "${enable_joiner}" = "yes"; then + enable_dtls="yes" + OPENTHREAD_ENABLE_DTLS=1 + MBEDTLS_CPPFLAGS="-I\${abs_top_srcdir}/third_party/mbedtls" + MBEDTLS_CPPFLAGS="${MBEDTLS_CPPFLAGS} -I\${abs_top_srcdir}/third_party/mbedtls/repo/include" + MBEDTLS_CPPFLAGS="${MBEDTLS_CPPFLAGS} -I\${abs_top_srcdir}/third_party/mbedtls/repo/include/mbedtls" + MBEDTLS_CPPFLAGS="${MBEDTLS_CPPFLAGS} -DMBEDTLS_CONFIG_FILE=\\\"mbedtls-config.h\\\"" +else + enable_dtls="no" + OPENTHREAD_ENABLE_DTLS=0 +fi + +AC_MSG_RESULT(${enable_dtls}) +AC_SUBST(OPENTHREAD_ENABLE_DTLS) +AM_CONDITIONAL([OPENTHREAD_ENABLE_DTLS], [test "${enable_dtls}" = "yes"]) +AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_DTLS],[${OPENTHREAD_ENABLE_DTLS}],[Define to 1 to enable dtls support.]) + # # Diagnostics Library # @@ -629,6 +708,7 @@ AC_CONFIG_FILES([ Makefile include/Makefile include/cli/Makefile +include/commissioning/Makefile include/ncp/Makefile include/platform/Makefile src/Makefile @@ -712,6 +792,9 @@ AC_MSG_NOTICE([ Pretty check args : ${PRETTY_CHECK_ARGS:--} OpenThread CLI support : ${enable_cli} OpenThread NCP support : ${enable_ncp} + OpenThread Commissioner support : ${enable_commissioner} + OpenThread Joiner support : ${enable_joiner} + OpenThread DTLS support : ${enable_dtls} OpenThread Diagnostics support : ${enable_diag} OpenThread examples : ${OPENTHREAD_EXAMPLES} OpenThread platform information : ${PLATFORM_INFO} diff --git a/include/Makefile.am b/include/Makefile.am index 62e26605b..9e4f50789 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -32,6 +32,7 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre.am DIST_SUBDIRS = \ cli \ + commissioning \ ncp \ platform \ $(NULL) @@ -40,6 +41,7 @@ DIST_SUBDIRS = \ SUBDIRS = \ cli \ + commissioning \ ncp \ platform \ $(NULL) @@ -48,6 +50,7 @@ SUBDIRS = \ PRETTY_SUBDIRS = \ cli \ + commissioning \ ncp \ platform \ $(NULL) diff --git a/include/commissioning/Makefile.am b/include/commissioning/Makefile.am new file mode 100644 index 000000000..e184f1552 --- /dev/null +++ b/include/commissioning/Makefile.am @@ -0,0 +1,41 @@ +# +# Copyright (c) 2016, Nest Labs, Inc. +# 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. +# + +include $(abs_top_nlbuild_autotools_dir)/automake/pre.am + +ot_commissioning_headers = \ + commissioner.h \ + joiner.h \ + $(NULL) + +ot_commissioningdir = $(includedir)/commissioning +dist_ot_commissioning_HEADERS = $(ot_commissioning_headers) + +install-headers: install-includeHEADERS + +include $(abs_top_nlbuild_autotools_dir)/automake/post.am diff --git a/include/commissioning/commissioner.h b/include/commissioning/commissioner.h new file mode 100644 index 000000000..811c10db6 --- /dev/null +++ b/include/commissioning/commissioner.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * @brief + * This file includes the platform abstraction for the Thread Commissioner role. + */ + +#ifndef OPENTHREAD_COMMISSIONER_H_ +#define OPENTHREAD_COMMISSIONER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup core-commissioning + * + * @{ + * + */ + +/** + * This function enables the Thread Commissioner role. + * + */ +ThreadError otCommissionerStart(void); + +/** + * This function disables the Thread Commissioner role. + * + */ +ThreadError otCommissionerStop(void); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // end of extern "C" +#endif + +#endif // OPENTHREAD_COMMISSIONER_H_ diff --git a/include/commissioning/joiner.h b/include/commissioning/joiner.h new file mode 100644 index 000000000..cbb2b5394 --- /dev/null +++ b/include/commissioning/joiner.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * @brief + * This file includes the platform abstraction for the Thread Joiner role. + */ + +#ifndef OPENTHREAD_JOINER_H_ +#define OPENTHREAD_JOINER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup core-commissioning + * + * @{ + * + */ + +/** + * This function enables the Thread Joiner role. + * + */ +ThreadError otJoinerStart(void); + +/** + * This function disables the Thread Joiner role. + * + */ +ThreadError otJoinerStop(void); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // end of extern "C" +#endif + +#endif // OPENTHREAD_JOINER_H_ diff --git a/include/openthread-types.h b/include/openthread-types.h index 828d8fdce..ca0e2576e 100644 --- a/include/openthread-types.h +++ b/include/openthread-types.h @@ -333,11 +333,19 @@ typedef enum otMeshcopTlvType OT_MESHCOP_TLV_NETWORKNAME = 3, ///< meshcop Network Name TLV OT_MESHCOP_TLV_PSKC = 4, ///< meshcop PSKc TLV OT_MESHCOP_TLV_MASTERKEY = 5, ///< meshcop Network Master Key TLV - OT_MESHCOP_TLV_LOCALPREFIX = 7, ///< meshcop Mesh Local Prefix TLV + OT_MESHCOP_TLV_MESHLOCALPREFIX = 7, ///< meshcop Mesh Local Prefix TLV + OT_MESHCOP_TLV_STEERING_DATA = 8, ///< meshcop Steering Data TLV + OT_MESHCOP_TLV_BORDER_AGENT_RLOC = 9, ///< meshcop Border Agent Locator TLV + OT_MESHCOP_TLV_COMMISSIONER_ID = 10, ///< meshcop Commissioner ID TLV + OT_MESHCOP_TLV_COMM_SESSION_ID = 11, ///< meshcop Commissioner Session ID TLV OT_MESHCOP_TLV_SECURITYPOLICY = 12, ///< meshcop Security Policy TLV OT_MESHCOP_TLV_GET = 13, ///< meshcop Get TLV OT_MESHCOP_TLV_ACTIVETIMESTAMP = 14, ///< meshcop Active Timestamp TLV OT_MESHCOP_TLV_STATE = 16, ///< meshcop State TLV + OT_MESHCOP_TLV_JOINER_DTLS = 17, ///< meshcop Joiner DTLS Encapsulation TLV + OT_MESHCOP_TLV_JOINER_UDP_PORT = 18, ///< meshcop Joiner UDP Port TLV + OT_MESHCOP_TLV_JOINER_IID = 19, ///< meshcop Joiner IID TLV + OT_MESHCOP_TLV_JOINER_ROUTER_KEK = 21, ///< meshcop Joiner Router KEK TLV OT_MESHCOP_TLV_PENDINGTIMESTAMP = 51, ///< meshcop Pending Timestamp TLV OT_MESHCOP_TLV_DELAYTIMER = 52, ///< meshcop Delay Timer TLV OT_MESHCOP_TLV_CHANNELMASK = 53, ///< meshcop Channel Mask TLV diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 924aa4fe0..8b00ecdc2 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -37,6 +37,8 @@ #include #include +#include +#include #include "cli.hpp" #include "cli_dataset.hpp" @@ -63,15 +65,24 @@ const struct Command Interpreter::sCommands[] = { "child", &ProcessChild }, { "childmax", &ProcessChildMax }, { "childtimeout", &ProcessChildTimeout }, +#if OPENTHREAD_ENABLE_COMMISSIONER + { "commissioner", &ProcessCommissioner }, +#endif { "contextreusedelay", &ProcessContextIdReuseDelay }, { "counter", &ProcessCounters }, { "dataset", &ProcessDataset }, +#if OPENTHREAD_ENABLE_DIAG + { "diag", &ProcessDiag }, +#endif { "discover", &ProcessDiscover }, { "eidcache", &ProcessEidCache }, { "extaddr", &ProcessExtAddress }, { "extpanid", &ProcessExtPanId }, { "ifconfig", &ProcessIfconfig }, { "ipaddr", &ProcessIpAddr }, +#if OPENTHREAD_ENABLE_JOINER + { "joiner", &ProcessJoiner }, +#endif { "keysequence", &ProcessKeySequence }, { "leaderdata", &ProcessLeaderData }, { "leaderpartitionid", &ProcessLeaderPartitionId }, @@ -101,9 +112,6 @@ const struct Command Interpreter::sCommands[] = { "thread", &ProcessThread }, { "version", &ProcessVersion }, { "whitelist", &ProcessWhitelist }, -#if OPENTHREAD_ENABLE_DIAG - { "diag", &ProcessDiag }, -#endif }; static otDEFINE_ALIGNED_VAR(sPingTimerBuf, sizeof(Timer), uint64_t); @@ -1818,6 +1826,52 @@ void Interpreter::ProcessVersion(int argc, char *argv[]) (void)argv; } +#if OPENTHREAD_ENABLE_COMMISSIONER + +void Interpreter::ProcessCommissioner(int argc, char *argv[]) +{ + ThreadError error = kThreadError_None; + + VerifyOrExit(argc > 0, error = kThreadError_Parse); + + if (strcmp(argv[0], "start") == 0) + { + otCommissionerStart(); + } + else if (strcmp(argv[0], "stop") == 0) + { + otCommissionerStop(); + } + +exit: + AppendResult(error); +} + +#endif // OPENTHREAD_ENABLE_COMMISSIONER + +#if OPENTHREAD_ENABLE_JOINER + +void Interpreter::ProcessJoiner(int argc, char *argv[]) +{ + ThreadError error = kThreadError_None; + + VerifyOrExit(argc > 0, error = kThreadError_Parse); + + if (strcmp(argv[0], "start") == 0) + { + otJoinerStart(); + } + else if (strcmp(argv[0], "stop") == 0) + { + otJoinerStop(); + } + +exit: + AppendResult(error); +} + +#endif // OPENTHREAD_ENABLE_JOINER + void Interpreter::ProcessWhitelist(int argc, char *argv[]) { ThreadError error = kThreadError_None; diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 4ad46f29e..9606096a5 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -36,10 +36,11 @@ #include +#include + #include #include #include -#include namespace Thread { @@ -135,9 +136,15 @@ private: static void ProcessChild(int argc, char *argv[]); static void ProcessChildTimeout(int argc, char *argv[]); static void ProcessChildMax(int argc, char *argv[]); +#if OPENTHREAD_ENABLE_COMMISSIONER + static void ProcessCommissioner(int argc, char *argv[]); +#endif // OPENTHREAD_ENABLE_COMMISSIONER static void ProcessContextIdReuseDelay(int argc, char *argv[]); static void ProcessCounters(int argc, char *argv[]); static void ProcessDataset(int argc, char *argv[]); +#if OPENTHREAD_ENABLE_DIAG + static void ProcessDiag(int argc, char *argv[]); +#endif // OPENTHREAD_ENABLE_DIAG static void ProcessDiscover(int argc, char *argv[]); static void ProcessEidCache(int argc, char *argv[]); static void ProcessExtAddress(int argc, char *argv[]); @@ -146,6 +153,9 @@ private: static void ProcessIpAddr(int argc, char *argv[]); static ThreadError ProcessIpAddrAdd(int argc, char *argv[]); static ThreadError ProcessIpAddrDel(int argc, char *argv[]); +#if OPENTHREAD_ENABLE_JOINER + static void ProcessJoiner(int argc, char *argv[]); +#endif // OPENTHREAD_ENABLE_JOINER static void ProcessKeySequence(int argc, char *argv[]); static void ProcessLeaderData(int argc, char *argv[]); static void ProcessLeaderPartitionId(int argc, char *argv[]); @@ -181,10 +191,6 @@ private: static void ProcessVersion(int argc, char *argv[]); static void ProcessWhitelist(int argc, char *argv[]); -#if OPENTHREAD_ENABLE_DIAG - static void ProcessDiag(int argc, char *argv[]); -#endif - static void HandleEchoResponse(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); static void HandlePingTimer(void *aContext); static void HandleActiveScanResult(otActiveScanResult *aResult, void *aContext); diff --git a/src/cli/cli_dataset.cpp b/src/cli/cli_dataset.cpp index 6f7edbeac..8b7df4fbc 100644 --- a/src/cli/cli_dataset.cpp +++ b/src/cli/cli_dataset.cpp @@ -507,7 +507,7 @@ ThreadError Dataset::ProcessMgmtGetCommand(int argc, char *argv[]) } else if (strcmp(argv[index], "localprefix") == 0) { - tlvs[length++] = OT_MESHCOP_TLV_LOCALPREFIX; + tlvs[length++] = OT_MESHCOP_TLV_MESHLOCALPREFIX; } else if (strcmp(argv[index], "delaytimer") == 0) { diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 34accd94f..e64112857 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -47,10 +47,13 @@ libopenthread_a_SOURCES = \ crypto/aes_ecb.cpp \ crypto/hmac_sha256.cpp \ crypto/mbedtls.cpp \ + crypto/sha256.cpp \ mac/mac.cpp \ mac/mac_frame.cpp \ mac/mac_whitelist.cpp \ mac/mac_blacklist.cpp \ + meshcop/joiner_router.cpp \ + meshcop/leader.cpp \ net/icmp6.cpp \ net/ip6.cpp \ net/ip6_address.cpp \ @@ -77,6 +80,24 @@ libopenthread_a_SOURCES = \ thread/thread_tlvs.cpp \ $(NULL) +if OPENTHREAD_ENABLE_COMMISSIONER +libopenthread_a_SOURCES += \ + meshcop/commissioner.cpp \ + $(NULL) +endif # OPENTHREAD_ENABLE_COMMISSIONER + +if OPENTHREAD_ENABLE_JOINER +libopenthread_a_SOURCES += \ + meshcop/joiner.cpp \ + $(NULL) +endif # OPENTHREAD_ENABLE_JOINER + +if OPENTHREAD_ENABLE_DTLS +libopenthread_a_SOURCES += \ + meshcop/dtls.cpp \ + $(NULL) +endif # OPENTHREAD_ENABLE_DTLS + noinst_HEADERS = \ openthread-core-config.h \ openthread-core-default-config.h \ @@ -94,10 +115,16 @@ noinst_HEADERS = \ crypto/aes_ecb.hpp \ crypto/hmac_sha256.hpp \ crypto/mbedtls.hpp \ + crypto/sha256.hpp \ mac/mac.hpp \ mac/mac_frame.hpp \ mac/mac_whitelist.hpp \ mac/mac_blacklist.hpp \ + meshcop/commissioner.hpp \ + meshcop/dtls.hpp \ + meshcop/joiner.hpp \ + meshcop/joiner_router.hpp \ + meshcop/leader.hpp \ net/icmp6.hpp \ net/ip6.hpp \ net/ip6_address.hpp \ diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index d848d6a58..4791ff421 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -552,6 +552,16 @@ void Message::SetMleDiscoverResponse(bool aMleDiscoverResponse) mInfo.mMleDiscoverResponse = aMleDiscoverResponse; } +bool Message::IsJoinerEntrust(void) const +{ + return mInfo.mJoinerEntrust; +} + +void Message::SetJoinerEntrust(bool aJoinerEntrust) +{ + mInfo.mJoinerEntrust = aJoinerEntrust; +} + uint16_t Message::UpdateChecksum(uint16_t aChecksum, uint16_t aOffset, uint16_t aLength) const { Buffer *curBuffer; diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp index e800f928e..8eac52d86 100644 --- a/src/core/common/message.hpp +++ b/src/core/common/message.hpp @@ -121,6 +121,7 @@ struct MessageInfo bool mLinkSecurity : 1; ///< Indicates whether or not link security is enabled. bool mMleDiscoverRequest : 1; ///< Identifies MLE Discover Request. bool mMleDiscoverResponse : 1; ///< Identifies MLE Discover Response. + bool mJoinerEntrust : 1; ///< Indicates whether or not this message is a Joiner Entrust. }; /** @@ -522,6 +523,23 @@ public: */ void SetMleDiscoverResponse(bool aMleDiscoverResponse); + /** + * This method indicates whether or not this message is an Joiner Entrust. + * + * @retval TRUE If this message is an Joiner Entrust. + * @retval FALSE If this message is not an Joiner Entrust. + * + */ + bool IsJoinerEntrust(void) const; + + /** + * This method sets whether or not this message is an Joiner Entrust. + * + * @param[in] aLinkSecurityEnabled TRUE if this message is an Joiner Entrust, FALSE otherwise. + * + */ + void SetJoinerEntrust(bool aJoinerEntrust); + /** * This method is used to update a checksum value. * diff --git a/src/core/crypto/mbedtls.hpp b/src/core/crypto/mbedtls.hpp index 75815400b..83e3349e4 100644 --- a/src/core/crypto/mbedtls.hpp +++ b/src/core/crypto/mbedtls.hpp @@ -34,8 +34,7 @@ #ifndef OT_MBEDTLS_HPP_ #define OT_MBEDTLS_HPP_ -#include - +#include #include namespace Thread { @@ -57,7 +56,11 @@ class MbedTls public: enum { - kMemorySize = 512, ///< Size of memory buffer (bytes). +#if OPENTHREAD_ENABLE_DTLS + kMemorySize = 2048 * sizeof(void *), ///< Size of memory buffer (bytes). +#else + kMemorySize = 512, ///< Size of memory buffer (bytes). +#endif }; /** diff --git a/src/core/crypto/sha256.cpp b/src/core/crypto/sha256.cpp new file mode 100644 index 000000000..7ccfec8ea --- /dev/null +++ b/src/core/crypto/sha256.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file implements SHA-256. + */ + +#include + +namespace Thread { +namespace Crypto { + +void Sha256::Start(void) +{ + mbedtls_sha256_init(&mContext); + mbedtls_sha256_starts(&mContext, 0); +} + +void Sha256::Update(const uint8_t *aBuf, uint16_t aBufLength) +{ + mbedtls_sha256_update(&mContext, aBuf, aBufLength); +} + +void Sha256::Finish(uint8_t aHash[kHashSize]) +{ + mbedtls_sha256_finish(&mContext, aHash); + mbedtls_sha256_free(&mContext); +} + +} // namespace Crypto +} // namespace Thread diff --git a/src/core/crypto/sha256.hpp b/src/core/crypto/sha256.hpp new file mode 100644 index 000000000..edd6d8231 --- /dev/null +++ b/src/core/crypto/sha256.hpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file includes definitions for performing SHA-256 computations. + */ + +#ifndef SHA256_HPP_ +#define SHA256_HPP_ + +#include + +#include + +namespace Thread { +namespace Crypto { + +/** + * @addtogroup core-security + * + * @{ + * + */ + +/** + * This class implements SHA-256 computation. + * + */ +class Sha256 +{ +public: + enum + { + kHashSize = 32, ///< SHA-256 hash size (bytes) + }; + + /** + * This method starts the SHA-256 computation. + * + */ + void Start(void); + + /** + * This method inputs bytes into the SHA-256 computation. + * + * @param[in] aBuf A pointer to the input buffer. + * @param[in] aBufLength The length of @p aBuf in bytes. + * + */ + void Update(const uint8_t *aBuf, uint16_t aBufLength); + + /** + * This method finalizes the hash computation. + * + * @param[out] aHash A pointer to the output buffer. + * + */ + void Finish(uint8_t aHash[kHashSize]); + +private: + mbedtls_sha256_context mContext; +}; + +/** + * @} + * + */ + +} // namespace Crypto +} // namespace Thread + +#endif // SHA256_HPP_ diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 4b0aa30fa..808cc7619 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -33,6 +33,8 @@ #include +#include + #include #include #include @@ -442,24 +444,46 @@ void Mac::HandleBeginTransmit(void *aContext) void Mac::ProcessTransmitSecurity(Frame &aFrame) { + uint32_t frameCounter; uint8_t securityLevel; + uint8_t keyIdMode; uint8_t nonce[kNonceSize]; uint8_t tagLength; Crypto::AesCcm aesCcm; + const uint8_t *key; if (aFrame.GetSecurityEnabled() == false) { ExitNow(); } + aFrame.GetKeyIdMode(keyIdMode); + + switch (keyIdMode) + { + case Frame::kKeyIdMode0: + key = mKeyManager.GetKek(); + frameCounter = mKeyManager.GetKekFrameCounter(); + break; + + case Frame::kKeyIdMode1: + key = mKeyManager.GetCurrentMacKey(); + frameCounter = mKeyManager.GetMacFrameCounter(); + mKeyManager.IncrementMacFrameCounter(); + aFrame.SetKeyId((mKeyManager.GetCurrentKeySequence() & 0x7f) + 1); + break; + + default: + assert(false); + break; + } + aFrame.GetSecurityLevel(securityLevel); - aFrame.SetFrameCounter(mKeyManager.GetMacFrameCounter()); + aFrame.SetFrameCounter(frameCounter); - aFrame.SetKeyId((mKeyManager.GetCurrentKeySequence() & 0x7f) + 1); + GenerateNonce(mExtAddress, frameCounter, securityLevel, nonce); - GenerateNonce(mExtAddress, mKeyManager.GetMacFrameCounter(), securityLevel, nonce); - - aesCcm.SetKey(mKeyManager.GetCurrentMacKey(), 16); + aesCcm.SetKey(key, 16); tagLength = aFrame.GetFooterLength() - Frame::kFcsSize; aesCcm.Init(aFrame.GetHeaderLength(), aFrame.GetPayloadLength(), tagLength, nonce, sizeof(nonce)); @@ -468,8 +492,6 @@ void Mac::ProcessTransmitSecurity(Frame &aFrame) aesCcm.Payload(aFrame.GetPayload(), aFrame.GetPayload(), aFrame.GetPayloadLength(), true); aesCcm.Finalize(aFrame.GetFooter(), &tagLength); - mKeyManager.IncrementMacFrameCounter(); - exit: {} } @@ -736,12 +758,13 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr, { ThreadError error = kThreadError_None; uint8_t securityLevel; + uint8_t keyIdMode; uint32_t frameCounter; uint8_t nonce[kNonceSize]; uint8_t tag[Frame::kMaxMicSize]; uint8_t tagLength; uint8_t keyid; - uint32_t keySequence; + uint32_t keySequence = 0; const uint8_t *macKey; Crypto::AesCcm aesCcm; @@ -752,44 +775,60 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr, ExitNow(); } - VerifyOrExit(aNeighbor != NULL, error = kThreadError_Security); - aFrame.GetSecurityLevel(securityLevel); aFrame.GetFrameCounter(frameCounter); - GenerateNonce(aSrcAddr.mExtAddress, frameCounter, securityLevel, nonce); + aFrame.GetKeyIdMode(keyIdMode); - tagLength = aFrame.GetFooterLength() - Frame::kFcsSize; + switch (keyIdMode) + { + case Frame::kKeyIdMode0: + VerifyOrExit((macKey = mKeyManager.GetKek()) != NULL, error = kThreadError_Security); + break; - aFrame.GetKeyId(keyid); - keyid--; + case Frame::kKeyIdMode1: + VerifyOrExit(aNeighbor != NULL, error = kThreadError_Security); - if (keyid == (mKeyManager.GetCurrentKeySequence() & 0x7f)) - { - // same key index - keySequence = mKeyManager.GetCurrentKeySequence(); - macKey = mKeyManager.GetCurrentMacKey(); - } - else if (keyid == ((mKeyManager.GetCurrentKeySequence() - 1) & 0x7f)) - { - // previous key index - keySequence = mKeyManager.GetCurrentKeySequence() - 1; - macKey = mKeyManager.GetTemporaryMacKey(keySequence); - } - else if (keyid == ((mKeyManager.GetCurrentKeySequence() + 1) & 0x7f)) - { - // next key index - keySequence = mKeyManager.GetCurrentKeySequence() + 1; - macKey = mKeyManager.GetTemporaryMacKey(keySequence); - } - else - { + aFrame.GetKeyId(keyid); + keyid--; + + if (keyid == (mKeyManager.GetCurrentKeySequence() & 0x7f)) + { + // same key index + keySequence = mKeyManager.GetCurrentKeySequence(); + macKey = mKeyManager.GetCurrentMacKey(); + } + else if (keyid == ((mKeyManager.GetCurrentKeySequence() - 1) & 0x7f)) + { + // previous key index + keySequence = mKeyManager.GetCurrentKeySequence() - 1; + macKey = mKeyManager.GetTemporaryMacKey(keySequence); + } + else if (keyid == ((mKeyManager.GetCurrentKeySequence() + 1) & 0x7f)) + { + // next key index + keySequence = mKeyManager.GetCurrentKeySequence() + 1; + macKey = mKeyManager.GetTemporaryMacKey(keySequence); + } + else + { + ExitNow(error = kThreadError_Security); + } + + VerifyOrExit((keySequence > aNeighbor->mKeySequence) || + ((keySequence == aNeighbor->mKeySequence) && + (frameCounter >= aNeighbor->mValid.mLinkFrameCounter)), + error = kThreadError_Security); + + break; + + default: ExitNow(error = kThreadError_Security); + break; } - VerifyOrExit((keySequence > aNeighbor->mKeySequence) || - ((keySequence == aNeighbor->mKeySequence) && (frameCounter >= aNeighbor->mValid.mLinkFrameCounter)), - error = kThreadError_Security); + GenerateNonce(aSrcAddr.mExtAddress, frameCounter, securityLevel, nonce); + tagLength = aFrame.GetFooterLength() - Frame::kFcsSize; aesCcm.SetKey(macKey, 16); aesCcm.Init(aFrame.GetHeaderLength(), aFrame.GetPayloadLength(), tagLength, nonce, sizeof(nonce)); @@ -799,21 +838,24 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr, VerifyOrExit(memcmp(tag, aFrame.GetFooter(), tagLength) == 0, error = kThreadError_Security); - if (aNeighbor->mKeySequence != keySequence) + if (keyIdMode == Frame::kKeyIdMode1) { - aNeighbor->mKeySequence = keySequence; - aNeighbor->mValid.mMleFrameCounter = 0; - } + if (aNeighbor->mKeySequence != keySequence) + { + aNeighbor->mKeySequence = keySequence; + aNeighbor->mValid.mMleFrameCounter = 0; + } - aNeighbor->mValid.mLinkFrameCounter = frameCounter + 1; + aNeighbor->mValid.mLinkFrameCounter = frameCounter + 1; + + if (keySequence > mKeyManager.GetCurrentKeySequence()) + { + mKeyManager.SetCurrentKeySequence(keySequence); + } + } aFrame.SetSecurityValid(true); - if (keySequence > mKeyManager.GetCurrentKeySequence()) - { - mKeyManager.SetCurrentKeySequence(keySequence); - } - exit: if (error != kThreadError_None) diff --git a/src/core/mac/mac_frame.cpp b/src/core/mac/mac_frame.cpp index d2e832bc0..62ff7bb58 100644 --- a/src/core/mac/mac_frame.cpp +++ b/src/core/mac/mac_frame.cpp @@ -556,6 +556,19 @@ exit: return error; } +ThreadError Frame::GetKeyIdMode(uint8_t &aKeyIdMode) +{ + ThreadError error = kThreadError_None; + uint8_t *buf; + + VerifyOrExit((buf = FindSecurityHeader()) != NULL, error = kThreadError_Parse); + + aKeyIdMode = buf[0] & kKeyIdModeMask; + +exit: + return error; +} + ThreadError Frame::GetFrameCounter(uint32_t &aFrameCounter) { ThreadError error = kThreadError_None; diff --git a/src/core/mac/mac_frame.hpp b/src/core/mac/mac_frame.hpp index 158cb3c32..7525783ee 100644 --- a/src/core/mac/mac_frame.hpp +++ b/src/core/mac/mac_frame.hpp @@ -419,6 +419,16 @@ public: */ ThreadError GetSecurityLevel(uint8_t &aSecurityLevel); + /** + * This method gets the Key Identifier Mode. + * + * @param[out] aSecurityLevel The Key Identifier Mode. + * + * @retval kThreadError_None Successfully retrieved the Key Identifier Mode. + * + */ + ThreadError GetKeyIdMode(uint8_t &aKeyIdMode); + /** * This method gets the Frame Counter. * diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp new file mode 100644 index 000000000..ce2e02413 --- /dev/null +++ b/src/core/meshcop/commissioner.cpp @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file implements a Commissioner role. + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Thread { +namespace MeshCoP { + +Commissioner::Commissioner(ThreadNetif &aThreadNetif): + mTimer(aThreadNetif.GetIp6().mTimerScheduler, HandleTimer, this), + mTransmitTask(aThreadNetif.GetIp6().mTaskletScheduler, &HandleUdpTransmit, this), + mSendKek(false), + mSocket(aThreadNetif.GetIp6().mUdp), + mRelayReceive(OPENTHREAD_URI_RELAY_RX, &HandleRelayReceive, this), + mNetif(aThreadNetif) +{ + aThreadNetif.GetCoapServer().AddResource(mRelayReceive); +} + +ThreadError Commissioner::Start(void) +{ + ThreadError error = kThreadError_None; + + VerifyOrExit(mState == kStateDisabled, error = kThreadError_InvalidState); + + SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this)); + mState = kStatePetition; + SendPetition(); + +exit: + return error; +} + +ThreadError Commissioner::Stop(void) +{ + mState = kStateDisabled; + SendKeepAlive(); + mTimer.Start(1000); + return kThreadError_None; +} + +void Commissioner::HandleTimer(void *aContext) +{ + static_cast(aContext)->HandleTimer(); +} + +void Commissioner::HandleTimer(void) +{ + switch (mState) + { + case kStateDisabled: + mSocket.Close(); + break; + + case kStatePetition: + SendPetition(); + break; + + case kStateActive: + SendKeepAlive(); + mTimer.Start(5000); + break; + } +} + +ThreadError Commissioner::SendPetition(void) +{ + ThreadError error = kThreadError_None; + Coap::Header header; + Message *message; + Ip6::MessageInfo messageInfo; + CommissionerIdTlv commissionerId; + + for (size_t i = 0; i < sizeof(mCoapToken); i++) + { + mCoapToken[i] = otPlatRandomGet() & 0xff; + } + + header.Init(); + header.SetVersion(1); + header.SetType(Coap::Header::kTypeConfirmable); + header.SetCode(Coap::Header::kCodePost); + header.SetMessageId(++mCoapMessageId); + header.SetToken(mCoapToken, sizeof(mCoapToken)); + header.AppendUriPathOptions(OPENTHREAD_URI_LEADER_PETITION); + header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + header.Finalize(); + + VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength())); + + commissionerId.Init(); + commissionerId.SetCommissionerId("OpenThread Commissioner"); + + SuccessOrExit(error = message->Append(&commissionerId, sizeof(Tlv) + commissionerId.GetLength())); + + memset(&messageInfo, 0, sizeof(messageInfo)); + mNetif.GetMle().GetLeaderAddress(*static_cast(&messageInfo.mPeerAddr)); + messageInfo.mPeerPort = kCoapUdpPort; + SuccessOrExit(error = mSocket.SendTo(*message, messageInfo)); + + otLogInfoMeshCoP("sent petition\r\n"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } + + return error; +} + +ThreadError Commissioner::SendKeepAlive(void) +{ + ThreadError error = kThreadError_None; + Coap::Header header; + Message *message; + Ip6::MessageInfo messageInfo; + StateTlv state; + CommissionerSessionIdTlv sessionId; + + for (size_t i = 0; i < sizeof(mCoapToken); i++) + { + mCoapToken[i] = otPlatRandomGet() & 0xff; + } + + header.Init(); + header.SetVersion(1); + header.SetType(Coap::Header::kTypeConfirmable); + header.SetCode(Coap::Header::kCodePost); + header.SetMessageId(++mCoapMessageId); + header.SetToken(mCoapToken, sizeof(mCoapToken)); + header.AppendUriPathOptions(OPENTHREAD_URI_LEADER_KEEP_ALIVE); + header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + header.Finalize(); + + VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength())); + + state.Init(); + state.SetState(mState == kStateActive ? StateTlv::kAccept : StateTlv::kReject); + SuccessOrExit(error = message->Append(&state, sizeof(state))); + + sessionId.Init(); + sessionId.SetCommissionerSessionId(mSessionId); + SuccessOrExit(error = message->Append(&sessionId, sizeof(sessionId))); + + memset(&messageInfo, 0, sizeof(messageInfo)); + mNetif.GetMle().GetLeaderAddress(*static_cast(&messageInfo.mPeerAddr)); + messageInfo.mPeerPort = kCoapUdpPort; + SuccessOrExit(error = mSocket.SendTo(*message, messageInfo)); + + otLogInfoMeshCoP("sent keep alive\r\n"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } + + return error; +} + +void Commissioner::HandleRelayReceive(void *aContext, Coap::Header &aHeader, + Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + static_cast(aContext)->HandleRelayReceive(aHeader, aMessage, aMessageInfo); +} + +void Commissioner::HandleRelayReceive(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + ThreadError error; + JoinerUdpPortTlv joinerPort; + JoinerIidTlv joinerIid; + uint16_t offset; + uint16_t length; + + VerifyOrExit(aHeader.GetType() == Coap::Header::kTypeNonConfirmable && + aHeader.GetCode() == Coap::Header::kCodePost, ;); + + otLogInfoMeshCoP("Received relay receive\r\n"); + + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kJoinerUdpPort, sizeof(joinerPort), joinerPort)); + VerifyOrExit(joinerPort.IsValid(), error = kThreadError_Parse); + + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kJoinerIid, sizeof(joinerIid), joinerIid)); + VerifyOrExit(joinerIid.IsValid(), error = kThreadError_Parse); + + SuccessOrExit(error = Tlv::GetValueOffset(aMessage, Tlv::kJoinerDtlsEncapsulation, offset, length)); + + memcpy(mJoinerIid, joinerIid.GetIid(), sizeof(mJoinerIid)); + mNetif.GetDtls().SetClientId(mJoinerIid, sizeof(mJoinerIid)); + mJoinerPort = joinerPort.GetUdpPort(); + mJoinerRouterAddress = aMessageInfo.GetPeerAddr(); + + mNetif.GetDtls().Receive(aMessage, offset, length); + +exit: + return; +} + +void Commissioner::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo) +{ + static_cast(aContext)->HandleUdpReceive(*static_cast(aMessage), + *static_cast(aMessageInfo)); +} + +void Commissioner::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + Coap::Header header; + StateTlv state; + CommissionerSessionIdTlv sessionId; + + SuccessOrExit(header.FromMessage(aMessage)); + VerifyOrExit(header.GetType() == Coap::Header::kTypeAcknowledgment && + header.GetCode() == Coap::Header::kCodeChanged && + header.GetMessageId() == mCoapMessageId && + header.GetTokenLength() == sizeof(mCoapToken) && + memcmp(mCoapToken, header.GetToken(), sizeof(mCoapToken)) == 0, ;); + aMessage.MoveOffset(header.GetLength()); + + SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kState, sizeof(state), state)); + VerifyOrExit(state.IsValid(), ;); + + VerifyOrExit(state.GetState() == StateTlv::kAccept, mState = kStateDisabled); + + switch (mState) + { + case kStateDisabled: + break; + + case kStatePetition: + SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kCommissionerSessionId, sizeof(sessionId), sessionId)); + VerifyOrExit(sessionId.IsValid(), ;); + + mSessionId = sessionId.GetCommissionerSessionId(); + mState = kStateActive; + mTimer.Start(5000); + + mNetif.GetDtls().Start(false, HandleDtlsReceive, HandleDtlsSend, this); + + otLogInfoMeshCoP("received petition response\r\n"); + break; + + case kStateActive: + otLogInfoMeshCoP("received keep alive response\r\n"); + break; + } + +exit: + (void)aMessageInfo; + return; +} + +ThreadError Commissioner::HandleDtlsSend(void *aContext, const uint8_t *aBuf, uint16_t aLength) +{ + otLogInfoMeshCoP("Commissioner::HandleDtlsTransmit\r\n"); + return static_cast(aContext)->HandleDtlsSend(aBuf, aLength); +} + +ThreadError Commissioner::HandleDtlsSend(const unsigned char *aBuf, uint16_t aLength) +{ + ThreadError error = kThreadError_None; + + if (mTransmitMessage == NULL) + { + Coap::Header header; + JoinerUdpPortTlv udpPort; + JoinerIidTlv iid; + ExtendedTlv tlv; + + VerifyOrExit((mTransmitMessage = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + + header.Init(); + header.SetVersion(1); + header.SetType(Coap::Header::kTypeNonConfirmable); + header.SetCode(Coap::Header::kCodePost); + header.SetMessageId(0); + header.SetToken(NULL, 0); + header.AppendUriPathOptions(OPENTHREAD_URI_RELAY_TX); + header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + header.Finalize(); + SuccessOrExit(error = mTransmitMessage->Append(header.GetBytes(), header.GetLength())); + + udpPort.Init(); + udpPort.SetUdpPort(mJoinerPort); + SuccessOrExit(error = mTransmitMessage->Append(&udpPort, sizeof(udpPort))); + + iid.Init(); + iid.SetIid(mJoinerIid); + SuccessOrExit(error = mTransmitMessage->Append(&iid, sizeof(iid))); + + if (mSendKek) + { + JoinerRouterKekTlv kek; + kek.Init(); + kek.SetKek(mNetif.GetKeyManager().GetKek()); + SuccessOrExit(error = mTransmitMessage->Append(&kek, sizeof(kek))); + } + + mTransmitMessage->SetOffset(mTransmitMessage->GetLength()); + + tlv.SetType(Tlv::kJoinerDtlsEncapsulation); + tlv.SetLength(0); + SuccessOrExit(error = mTransmitMessage->Append(&tlv, sizeof(tlv))); + } + + VerifyOrExit(mTransmitMessage->Append(aBuf, aLength) == kThreadError_None, error = kThreadError_NoBufs); + + mTransmitTask.Post(); + +exit: + + if (error != kThreadError_None && mTransmitMessage != NULL) + { + mTransmitMessage->Free(); + } + + return error; +} + +void Commissioner::HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength) +{ + otLogInfoMeshCoP("Commissioner::HandleDtlsReceive\r\n"); + static_cast(aContext)->HandleDtlsReceive(aBuf, aLength); +} + +void Commissioner::HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength) +{ + ReceiveJoinerFinalize(aBuf, aLength); +} + +void Commissioner::HandleUdpTransmit(void *aContext) +{ + otLogInfoMeshCoP("Commissioner::HandleUdpTransmit\r\n"); + static_cast(aContext)->HandleUdpTransmit(); +} + +void Commissioner::HandleUdpTransmit(void) +{ + ThreadError error = kThreadError_None; + Ip6::MessageInfo messageInfo; + ExtendedTlv tlv; + + VerifyOrExit(mTransmitMessage != NULL, error = kThreadError_NoBufs); + + tlv.SetType(Tlv::kJoinerDtlsEncapsulation); + tlv.SetLength(mTransmitMessage->GetLength() - mTransmitMessage->GetOffset() - sizeof(tlv)); + mTransmitMessage->Write(mTransmitMessage->GetOffset(), sizeof(tlv), &tlv); + + memset(&messageInfo, 0, sizeof(messageInfo)); + messageInfo.GetPeerAddr() = mJoinerRouterAddress; + messageInfo.mPeerPort = kCoapUdpPort; + messageInfo.mInterfaceId = 1; + + SuccessOrExit(error = mSocket.SendTo(*mTransmitMessage, messageInfo)); + +exit: + + if (error != kThreadError_None && mTransmitMessage != NULL) + { + mTransmitMessage->Free(); + } + + mTransmitMessage = NULL; +} + +void Commissioner::ReceiveJoinerFinalize(uint8_t *buf, uint16_t length) +{ + Message *message; + Coap::Header header; + char uriPath[16]; + char *curUriPath = uriPath; + const Coap::Header::Option *coapOption; + + otLogInfoMeshCoP("receive joiner finalize 1\r\n"); + + VerifyOrExit((message = mNetif.GetIp6().mMessagePool.New(Message::kTypeIp6, 0)) != NULL, ;); + SuccessOrExit(message->Append(buf, length)); + SuccessOrExit(header.FromMessage(*message)); + message->SetOffset(header.GetLength()); + + coapOption = header.GetCurrentOption(); + + while (coapOption != NULL) + { + switch (coapOption->mNumber) + { + case Coap::Header::Option::kOptionUriPath: + VerifyOrExit(coapOption->mLength < sizeof(uriPath) - static_cast(curUriPath - uriPath), ;); + memcpy(curUriPath, coapOption->mValue, coapOption->mLength); + curUriPath[coapOption->mLength] = '/'; + curUriPath += coapOption->mLength + 1; + break; + + case Coap::Header::Option::kOptionContentFormat: + break; + + default: + ExitNow(); + } + + coapOption = header.GetNextOption(); + } + + curUriPath[-1] = '\0'; + + SendJoinFinalizeResponse(header); + +exit: + return; +} + +void Commissioner::SendJoinFinalizeResponse(const Coap::Header &aRequestHeader) +{ + Coap::Header responseHeader; + MeshCoP::StateTlv *stateTlv; + uint8_t buf[128]; + uint8_t *cur = buf; + + responseHeader.Init(); + responseHeader.SetVersion(1); + responseHeader.SetType(Coap::Header::kTypeAcknowledgment); + responseHeader.SetCode(Coap::Header::kCodeChanged); + responseHeader.SetMessageId(aRequestHeader.GetMessageId()); + responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength()); + responseHeader.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + responseHeader.Finalize(); + memcpy(cur, responseHeader.GetBytes(), responseHeader.GetLength()); + cur += responseHeader.GetLength(); + + stateTlv = reinterpret_cast(cur); + stateTlv->Init(); + stateTlv->SetState(MeshCoP::StateTlv::kAccept); + cur += sizeof(*stateTlv); + + mSendKek = true; + mNetif.GetDtls().Send(buf, static_cast(cur - buf)); + mSendKek = false; + + otLogInfoMeshCoP("sent joiner finalize response\r\n"); +} + +} // namespace MeshCoP +} // namespace Thread diff --git a/src/core/meshcop/commissioner.hpp b/src/core/meshcop/commissioner.hpp new file mode 100644 index 000000000..0e95a3679 --- /dev/null +++ b/src/core/meshcop/commissioner.hpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file includes definitions for the Commissioner role. + */ + +#ifndef COMMISSIONER_HPP_ +#define COMMISSIONER_HPP_ + +#include +#include +#include +#include + +namespace Thread { + +class ThreadNetif; + +namespace MeshCoP { + +class Commissioner +{ +public: + /** + * This constructor initializes the Commissioner object. + * + * @param[in] aThreadNetif A reference to the Thread network interface. + * + */ + Commissioner(ThreadNetif &aThreadNetif); + + /** + * This method starts the Commissioner service. + * + * @retval kThreadError_None Successfully started the Commissioner service. + * + */ + ThreadError Start(void); + + /** + * This method stops the Commissioner service. + * + * @retval kThreadError_None Successfully stopped the Commissioner service. + * + */ + ThreadError Stop(void); + +private: + static void HandleTimer(void *aContext); + void HandleTimer(void); + + static void HandleRelayReceive(void *aContext, Coap::Header &aHeader, + Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + void HandleRelayReceive(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo); + void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + static void HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength); + void HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength); + + static ThreadError HandleDtlsSend(void *aContext, const uint8_t *aBuf, uint16_t aLength); + ThreadError HandleDtlsSend(const uint8_t *aBuf, uint16_t aLength); + + static void HandleUdpTransmit(void *aContext); + void HandleUdpTransmit(void); + + void ReceiveJoinerFinalize(uint8_t *buf, uint16_t length); + void SendJoinFinalizeResponse(const Coap::Header &aRequestHeader); + + ThreadError SendPetition(void); + ThreadError SendKeepAlive(void); + + enum + { + kStateDisabled = 0, + kStatePetition = 1, + kStateActive = 2, + }; + + uint8_t mState; + + Ip6::Address mJoinerRouterAddress; + uint8_t mJoinerIid[8]; + uint16_t mJoinerPort; + + uint16_t mSessionId; + Message *mTransmitMessage; + Timer mTimer; + Tasklet mTransmitTask; + bool mSendKek; + + Ip6::UdpSocket mSocket; + uint8_t mCoapToken[2]; + uint16_t mCoapMessageId; + + Coap::Resource mRelayReceive; + ThreadNetif &mNetif; +}; + +} // namespace MeshCoP +} // namespace Thread + +#endif // COMMISSIONER_HPP_ diff --git a/src/core/meshcop/dtls.cpp b/src/core/meshcop/dtls.cpp new file mode 100644 index 000000000..46dad992d --- /dev/null +++ b/src/core/meshcop/dtls.cpp @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file implements the necessary hooks for mbedTLS. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace Thread { +namespace MeshCoP { + +Dtls::Dtls(ThreadNetif &aNetif): + mStarted(false), + mTimer(aNetif.GetIp6().mTimerScheduler, &HandleTimer, this), + mTimerIntermediate(0), + mTimerSet(false), + mNetif(aNetif) +{ +} + +ThreadError Dtls::Start(bool aClient, ReceiveHandler aReceiveHandler, SendHandler aSendHandler, void *aContext) +{ + static const int ciphersuites[2] = {0xC0FF, 0}; // EC-JPAKE cipher suite + int rval; + + mReceiveHandler = aReceiveHandler; + mSendHandler = aSendHandler; + mContext = aContext; + mClient = aClient; + + mbedtls_ssl_init(&mSsl); + mbedtls_ssl_config_init(&mConf); + mbedtls_ctr_drbg_init(&mCtrDrbg); + mbedtls_entropy_init(&mEntropy); + + mbedtls_debug_set_threshold(4); + + // XXX: should set personalization data to hardware address + rval = mbedtls_ctr_drbg_seed(&mCtrDrbg, mbedtls_entropy_func, &mEntropy, NULL, 0); + VerifyOrExit(rval == 0, ;); + + rval = mbedtls_ssl_config_defaults(&mConf, mClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT); + VerifyOrExit(rval == 0, ;); + + mbedtls_ssl_conf_rng(&mConf, mbedtls_ctr_drbg_random, &mCtrDrbg); + mbedtls_ssl_conf_min_version(&mConf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); + mbedtls_ssl_conf_max_version(&mConf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); + mbedtls_ssl_conf_ciphersuites(&mConf, ciphersuites); + mbedtls_ssl_conf_export_keys_cb(&mConf, HandleMbedtlsExportKeys, this); + mbedtls_ssl_conf_handshake_timeout(&mConf, 8000, 60000); + mbedtls_ssl_conf_dbg(&mConf, HandleMbedtlsDebug, stdout); + + if (!mClient) + { + mbedtls_ssl_cookie_init(&mCookieCtx); + + rval = mbedtls_ssl_cookie_setup(&mCookieCtx, mbedtls_ctr_drbg_random, &mCtrDrbg); + VerifyOrExit(rval == 0, ;); + + mbedtls_ssl_conf_dtls_cookies(&mConf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &mCookieCtx); + } + + rval = mbedtls_ssl_setup(&mSsl, &mConf); + VerifyOrExit(rval == 0, ;); + + mbedtls_ssl_set_bio(&mSsl, this, &HandleMbedtlsTransmit, HandleMbedtlsReceive, NULL); + mbedtls_ssl_set_timer_cb(&mSsl, this, &HandleMbedtlsSetTimer, HandleMbedtlsGetTimer); + + rval = mbedtls_ssl_set_hs_ecjpake_password(&mSsl, (const unsigned char *)"threadjpaketest", 15); + VerifyOrExit(rval == 0, ;); + + mStarted = true; + Process(); + + otLogInfoMeshCoP("DTLS started\r\n"); + +exit: + return MapError(rval); +} + +ThreadError Dtls::Stop(void) +{ + mStarted = false; + mbedtls_ssl_close_notify(&mSsl); + mbedtls_ssl_free(&mSsl); + mbedtls_ssl_config_free(&mConf); + mbedtls_ctr_drbg_free(&mCtrDrbg); + mbedtls_entropy_free(&mEntropy); + mbedtls_ssl_cookie_free(&mCookieCtx); + return kThreadError_None; +} + +ThreadError Dtls::SetClientId(const uint8_t *aClientId, uint8_t aLength) +{ + int rval = mbedtls_ssl_set_client_transport_id(&mSsl, aClientId, aLength); + return MapError(rval); +} + +bool Dtls::IsConnected(void) +{ + return mSsl.state == MBEDTLS_SSL_HANDSHAKE_OVER; +} + +ThreadError Dtls::Send(const uint8_t *aBuf, uint16_t aLength) +{ + int rval = mbedtls_ssl_write(&mSsl, aBuf, aLength); + return MapError(rval); +} + +ThreadError Dtls::Receive(Message &aMessage, uint16_t aOffset, uint16_t aLength) +{ + mReceiveMessage = &aMessage; + mReceiveOffset = aOffset; + mReceiveLength = aLength; + + Process(); + + return kThreadError_None; +} + +int Dtls::HandleMbedtlsTransmit(void *aContext, const unsigned char *aBuf, size_t aLength) +{ + return static_cast(aContext)->HandleMbedtlsTransmit(aBuf, aLength); +} + +int Dtls::HandleMbedtlsTransmit(const unsigned char *aBuf, size_t aLength) +{ + ThreadError error; + int rval; + + otLogInfoMeshCoP("Dtls::HandleMbedtlsTransmit\r\n"); + + error = mSendHandler(mContext, aBuf, (uint16_t)aLength); + + switch (error) + { + case kThreadError_None: + rval = static_cast(aLength); + break; + + case kThreadError_NoBufs: + rval = MBEDTLS_ERR_SSL_WANT_WRITE; + break; + + default: + assert(false); + break; + } + + return rval; +} + +int Dtls::HandleMbedtlsReceive(void *aContext, unsigned char *aBuf, size_t aLength) +{ + return static_cast(aContext)->HandleMbedtlsReceive(aBuf, aLength); +} + +int Dtls::HandleMbedtlsReceive(unsigned char *aBuf, size_t aLength) +{ + int rval; + + otLogInfoMeshCoP("Dtls::HandleMbedtlsReceive\r\n"); + + VerifyOrExit(mReceiveMessage != NULL && mReceiveLength != 0, rval = MBEDTLS_ERR_SSL_WANT_READ); + + if (aLength > mReceiveLength) + { + aLength = mReceiveLength; + } + + rval = (int)mReceiveMessage->Read(mReceiveOffset, (uint16_t)aLength, aBuf); + mReceiveOffset += rval; + mReceiveLength -= rval; + +exit: + return rval; +} + +int Dtls::HandleMbedtlsGetTimer(void *aContext) +{ + return static_cast(aContext)->HandleMbedtlsGetTimer(); +} + +int Dtls::HandleMbedtlsGetTimer(void) +{ + int rval; + + otLogInfoMeshCoP("Dtls::HandleMbedtlsGetTimer\r\n"); + + if (!mTimerSet) + { + rval = -1; + } + else if (!mTimer.IsRunning()) + { + rval = 2; + } + else if (static_cast(mTimerIntermediate - Timer::GetNow()) <= 0) + { + rval = 1; + } + else + { + rval = 0; + } + + return rval; +} + +void Dtls::HandleMbedtlsSetTimer(void *aContext, uint32_t aIntermediate, uint32_t aFinish) +{ + static_cast(aContext)->HandleMbedtlsSetTimer(aIntermediate, aFinish); +} + +void Dtls::HandleMbedtlsSetTimer(uint32_t aIntermediate, uint32_t aFinish) +{ + otLogInfoMeshCoP("Dtls::SetTimer\r\n"); + + if (aFinish == 0) + { + mTimerSet = false; + mTimer.Stop(); + } + else + { + mTimerSet = true; + mTimer.Start(aFinish); + mTimerIntermediate = Timer::GetNow() + aIntermediate; + } +} + +int Dtls::HandleMbedtlsExportKeys(void *aContext, const unsigned char *aMasterSecret, const unsigned char *aKeyBlock, + size_t aMacLength, size_t aKeyLength, size_t aIvLength) +{ + return static_cast(aContext)->HandleMbedtlsExportKeys(aMasterSecret, aKeyBlock, + aMacLength, aKeyLength, aIvLength); +} + +int Dtls::HandleMbedtlsExportKeys(const unsigned char *aMasterSecret, const unsigned char *aKeyBlock, + size_t aMacLength, size_t aKeyLength, size_t aIvLength) +{ + uint8_t kek[Crypto::Sha256::kHashSize]; + Crypto::Sha256 sha256; + + sha256.Start(); + sha256.Update(aKeyBlock, static_cast(aMacLength + aKeyLength + aIvLength)); + sha256.Finish(kek); + + mNetif.GetKeyManager().SetKek(kek); + + otLogInfoMeshCoP("Generated KEK\r\n"); + + (void)aMasterSecret; + return 0; +} + +void Dtls::HandleTimer(void *aContext) +{ + static_cast(aContext)->HandleTimer(); +} + +void Dtls::HandleTimer(void) +{ + Process(); +} + +void Dtls::Process(void) +{ + uint8_t buf[MBEDTLS_SSL_MAX_CONTENT_LEN]; + int rval; + + while (mStarted) + { + if (mSsl.state != MBEDTLS_SSL_HANDSHAKE_OVER) + { + rval = mbedtls_ssl_handshake(&mSsl); + } + else + { + rval = mbedtls_ssl_read(&mSsl, buf, sizeof(buf)); + } + + if (rval > 0) + { + mReceiveHandler(mContext, buf, static_cast(rval)); + } + else if (rval == 0 || rval == MBEDTLS_ERR_SSL_WANT_READ || rval == MBEDTLS_ERR_SSL_WANT_WRITE) + { + break; + } + else + { + mbedtls_ssl_session_reset(&mSsl); + mbedtls_ssl_set_hs_ecjpake_password(&mSsl, (const unsigned char *)"threadjpaketest", 15); + break; + } + } +} + +ThreadError Dtls::MapError(int rval) +{ + ThreadError error; + + switch (rval) + { + case MBEDTLS_ERR_SSL_BAD_INPUT_DATA: + error = kThreadError_InvalidArgs; + break; + + case MBEDTLS_ERR_SSL_ALLOC_FAILED: + error = kThreadError_NoBufs; + break; + + default: + if (rval >= 0) + { + error = kThreadError_None; + } + else + { + assert(false); + } + + break; + } + + return error; +} + +void Dtls::HandleMbedtlsDebug(void *ctx, int level, const char *file, int line, const char *str) +{ + otLogInfoMeshCoP("%s:%04d: %s\r\n", file, line, str); + (void)ctx; + (void)level; + (void)file; + (void)line; + (void)str; +} + +} // namespace MeshCoP +} // namespace Thread diff --git a/src/core/meshcop/dtls.hpp b/src/core/meshcop/dtls.hpp new file mode 100644 index 000000000..c266df29b --- /dev/null +++ b/src/core/meshcop/dtls.hpp @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file includes definitions for using mbedTLS. + */ + +#ifndef DTLS_HPP_ +#define DTLS_HPP_ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Thread { + +class ThreadNetif; + +namespace MeshCoP { + +class Dtls +{ +public: + /** + * This constructor initializes the DTLS object. + * + * @param[in] aNetif A reference to the Thread network interface. + * + */ + Dtls(ThreadNetif &aNetif); + + /** + * This function pointer is called when data is received from the DTLS session. + * + * @param[in] aContext A pointer to application-specific context. + * @param[in] aBuf A pointer to the received data buffer. + * @param[in] aLength Number of bytes in the received data buffer. + * + */ + typedef void (*ReceiveHandler)(void *aContext, uint8_t *aBuf, uint16_t aLength); + + /** + * This function pointer is called when data is ready to transmit for the DTLS session. + * + * @param[in] aContext A pointer to application-specific context. + * @param[in] aBuf A pointer to the transmit data buffer. + * @param[in] aLength Number of bytes in the transmit data buffer. + * + */ + typedef ThreadError(*SendHandler)(void *aContext, const uint8_t *aBuf, uint16_t aLength); + + /** + * This method starts the DTLS service. + * + * @param[in] aClient TRUE if operating as a client, FALSE if operating as a server. + * @param[in] aReceiveHandler A pointer to the receive handler. + * @param[in] aSendHandler A pointer to the send handler. + * @param[in] aContext A pointer to application-specific context. + * + * @retval kThreadError_None Successfully started the DTLS service. + * + */ + ThreadError Start(bool aClient, ReceiveHandler aReceiveHandler, SendHandler aSendHandler, void *aContext); + + /** + * This method stops the DTLS service. + * + * @retval kThreadError_None Successfully stopped the DTLS service. + * + */ + ThreadError Stop(void); + + /** + * This method sets the Client ID used for generating the Hello Cookie. + * + * @param[in] aClientId A pointer to the Client ID. + * @param[in] aLength Number of bytes in the Client ID. + * + * @retval kThreadError_None Successfully set the Client ID. + * + */ + ThreadError SetClientId(const uint8_t *aClientId, uint8_t aLength); + + /** + * This method indicates whether or not the DTLS session is connected. + * + * @retval TRUE The DTLS session is connected. + * @retval FALSE The DTLS session is not connected. + * + */ + bool IsConnected(void); + + /** + * This method sends data within the DTLS session. + * + * @param[in] aBuf A pointer to the data buffer. + * @param[in] aLength Number of bytes in the data buffer. + * + * @retval kThreadError_None Successfully sent the data via the DTLS session. + * + */ + ThreadError Send(const uint8_t *aBuf, uint16_t aLength); + + /** + * This method provides a received DTLS message to the DTLS object. + * + * @param[in] aMessage A reference to the message. + * @param[in] aOffset The offset within @p aMessage where the DTLS message starts. + * @param[in] aLength The size of the DTLS message (bytes). + * + * @retval kThreadError_None Successfully processed the received DTLS message. + * + */ + ThreadError Receive(Message &aMessage, uint16_t aOffset, uint16_t aLength); + +private: + static ThreadError MapError(int rval); + + static void HandleMbedtlsDebug(void *ctx, int level, const char *file, int line, const char *str); + + static int HandleMbedtlsGetTimer(void *aContext); + int HandleMbedtlsGetTimer(void); + + static void HandleMbedtlsSetTimer(void *aContext, uint32_t aIntermediate, uint32_t aFinish); + void HandleMbedtlsSetTimer(uint32_t aIntermediate, uint32_t aFinish); + + static int HandleMbedtlsReceive(void *aContext, unsigned char *aBuf, size_t aLength); + int HandleMbedtlsReceive(unsigned char *aBuf, size_t aLength); + + static int HandleMbedtlsTransmit(void *aContext, const unsigned char *aBuf, size_t aLength); + int HandleMbedtlsTransmit(const unsigned char *aBuf, size_t aLength); + + static int HandleMbedtlsExportKeys(void *aContext, const unsigned char *aMasterSecret, + const unsigned char *aKeyBlock, + size_t aMacLength, size_t aKeyLength, size_t aIvLength); + int HandleMbedtlsExportKeys(const unsigned char *aMasterSecret, const unsigned char *aKeyBlock, + size_t aMacLength, size_t aKeyLength, size_t aIvLength); + + static void HandleTimer(void *aContext); + void HandleTimer(void); + + void Process(void); + + mbedtls_entropy_context mEntropy; + mbedtls_ctr_drbg_context mCtrDrbg; + mbedtls_ssl_context mSsl; + mbedtls_ssl_config mConf; + mbedtls_ssl_cookie_ctx mCookieCtx; + bool mStarted; + + Timer mTimer; + uint32_t mTimerIntermediate; + bool mTimerSet; + + Message *mReceiveMessage; + uint16_t mReceiveOffset; + uint16_t mReceiveLength; + + ReceiveHandler mReceiveHandler; + SendHandler mSendHandler; + void *mContext; + bool mClient; + + ThreadNetif &mNetif; +}; + +} // namspace MeshCoP +} // namespace Thread + +#endif // DTLS_HPP_ diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp new file mode 100644 index 000000000..6234bc191 --- /dev/null +++ b/src/core/meshcop/joiner.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file implements the Joiner role. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +using Thread::Encoding::BigEndian::HostSwap16; + +namespace Thread { +namespace MeshCoP { + +Joiner::Joiner(ThreadNetif &aNetif): + mTransmitMessage(NULL), + mSocket(aNetif.GetIp6().mUdp), + mTransmitTask(aNetif.GetIp6().mTaskletScheduler, &HandleUdpTransmit, this), + mJoinerEntrust(OPENTHREAD_URI_JOINER_ENTRUST, &HandleJoinerEntrust, this), + mNetif(aNetif) +{ + mNetif.GetCoapServer().AddResource(mJoinerEntrust); +} + +ThreadError Joiner::Start(void) +{ + return mNetif.GetMle().Discover(0, 0, OT_PANID_BROADCAST, HandleDiscoverResult, this); +} + +void Joiner::HandleDiscoverResult(otActiveScanResult *aResult, void *aContext) +{ + static_cast(aContext)->HandleDiscoverResult(aResult); +} + +void Joiner::HandleDiscoverResult(otActiveScanResult *aResult) +{ + if (aResult != NULL) + { + memcpy(&mJoinerRouter, &aResult->mExtAddress, sizeof(mJoinerRouter)); + } + else + { + // open UDP port + Ip6::SockAddr sockaddr; + sockaddr.mPort = 1000; + mSocket.Open(&HandleUdpReceive, this); + mSocket.Bind(sockaddr); + + mNetif.GetIp6Filter().AddUnsecurePort(sockaddr.mPort); + + mNetif.GetDtls().Start(true, HandleDtlsReceive, HandleDtlsSend, this); + } +} + +ThreadError Joiner::Stop(void) +{ + return kThreadError_NotImplemented; +} + +ThreadError Joiner::HandleDtlsSend(void *aContext, const uint8_t *aBuf, uint16_t aLength) +{ + otLogInfoMeshCoP("Joiner::HandleDtlsTransmit\r\n"); + return static_cast(aContext)->HandleDtlsSend(aBuf, aLength); +} + +ThreadError Joiner::HandleDtlsSend(const unsigned char *aBuf, uint16_t aLength) +{ + ThreadError error = kThreadError_None; + + if (mTransmitMessage == NULL) + { + VerifyOrExit((mTransmitMessage = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + mTransmitMessage->SetLinkSecurityEnabled(false); + } + + VerifyOrExit(mTransmitMessage->Append(aBuf, aLength) == kThreadError_None, error = kThreadError_NoBufs); + + mTransmitTask.Post(); + +exit: + + if (error != kThreadError_None && mTransmitMessage != NULL) + { + mTransmitMessage->Free(); + } + + return error; +} + +void Joiner::HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength) +{ + otLogInfoMeshCoP("Joiner::HandleDtlsReceive\r\n"); + static_cast(aContext)->HandleDtlsReceive(aBuf, aLength); +} + +void Joiner::HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength) +{ + ReceiveJoinerFinalizeResponse(aBuf, aLength); +} + +void Joiner::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo) +{ + otLogInfoMeshCoP("Joiner::HandleUdpReceive\r\n"); + static_cast(aContext)->HandleUdpReceive(*static_cast(aMessage), + *static_cast(aMessageInfo)); +} + +void Joiner::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + (void)aMessageInfo; + + mNetif.GetDtls().Receive(aMessage, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset()); + + if (mNetif.GetDtls().IsConnected()) + { + SendJoinerFinalize(); + } +} + +void Joiner::HandleUdpTransmit(void *aContext) +{ + otLogInfoMeshCoP("Joiner::HandleUdpTransmit\r\n"); + static_cast(aContext)->HandleUdpTransmit(); +} + +void Joiner::HandleUdpTransmit(void) +{ + ThreadError error = kThreadError_None; + Ip6::MessageInfo messageInfo; + + VerifyOrExit(mTransmitMessage != NULL, error = kThreadError_NoBufs); + + otLogInfoMeshCoP("transmit %d\r\n", mTransmitMessage->GetLength()); + + memset(&messageInfo, 0, sizeof(messageInfo)); + messageInfo.GetPeerAddr().mFields.m16[0] = HostSwap16(0xfe80); + messageInfo.GetPeerAddr().SetIid(mJoinerRouter); + messageInfo.mPeerPort = 1000; + messageInfo.mInterfaceId = 1; + + SuccessOrExit(error = mSocket.SendTo(*mTransmitMessage, messageInfo)); + +exit: + + if (error != kThreadError_None && mTransmitMessage != NULL) + { + mTransmitMessage->Free(); + } + + mTransmitMessage = NULL; +} + +void Joiner::SendJoinerFinalize(void) +{ + Coap::Header header; + MeshCoP::StateTlv *stateTlv; + uint8_t buf[128]; + uint8_t *cur = buf; + + header.Init(); + header.SetVersion(1); + header.SetType(Coap::Header::kTypeConfirmable); + header.SetCode(Coap::Header::kCodePost); + header.SetMessageId(0); + header.SetToken(NULL, 0); + header.AppendUriPathOptions(OPENTHREAD_URI_JOINER_FINALIZE); + header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + header.Finalize(); + memcpy(cur, header.GetBytes(), header.GetLength()); + cur += header.GetLength(); + + stateTlv = reinterpret_cast(cur); + stateTlv->Init(); + stateTlv->SetState(MeshCoP::StateTlv::kAccept); + cur += sizeof(*stateTlv); + + mNetif.GetDtls().Send(buf, static_cast(cur - buf)); + + otLogInfoMeshCoP("Sent joiner finalize\r\n"); +} + +void Joiner::ReceiveJoinerFinalizeResponse(uint8_t *buf, uint16_t length) +{ + Message *message; + Coap::Header header; + + VerifyOrExit((message = mNetif.GetIp6().mMessagePool.New(Message::kTypeIp6, 0)) != NULL, ;); + SuccessOrExit(message->Append(buf, length)); + SuccessOrExit(header.FromMessage(*message)); + + VerifyOrExit(header.GetType() == Coap::Header::kTypeAcknowledgment && + header.GetCode() == Coap::Header::kCodeChanged && + header.GetMessageId() == 0 && + header.GetTokenLength() == 0, ;); + + otLogInfoMeshCoP("received joiner finalize response\r\n"); + + Close(); + +exit: + return; +} + +void Joiner::HandleJoinerEntrust(void *aContext, Coap::Header &aHeader, + Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + static_cast(aContext)->HandleJoinerEntrust(aHeader, aMessage, aMessageInfo); +} + +void Joiner::HandleJoinerEntrust(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + ThreadError error; + + NetworkMasterKeyTlv masterKey; + MeshLocalPrefixTlv meshLocalPrefix; + ExtendedPanIdTlv extendedPanId; + NetworkNameTlv networkName; + ActiveTimestampTlv activeTimestamp; + + VerifyOrExit(aHeader.GetType() == Coap::Header::kTypeConfirmable && + aHeader.GetCode() == Coap::Header::kCodePost, error = kThreadError_Drop); + + otLogInfoMeshCoP("Received joiner entrust\r\n"); + + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kNetworkMasterKey, sizeof(masterKey), masterKey)); + VerifyOrExit(masterKey.IsValid(), error = kThreadError_Parse); + + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kMeshLocalPrefix, sizeof(meshLocalPrefix), meshLocalPrefix)); + VerifyOrExit(meshLocalPrefix.IsValid(), error = kThreadError_Parse); + + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kExtendedPanId, sizeof(extendedPanId), extendedPanId)); + VerifyOrExit(extendedPanId.IsValid(), error = kThreadError_Parse); + + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kNetworkName, sizeof(networkName), networkName)); + VerifyOrExit(networkName.IsValid(), error = kThreadError_Parse); + + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kActiveTimestamp, sizeof(activeTimestamp), activeTimestamp)); + VerifyOrExit(activeTimestamp.IsValid(), error = kThreadError_Parse); + + mNetif.GetKeyManager().SetMasterKey(masterKey.GetNetworkMasterKey(), masterKey.GetLength()); + mNetif.GetMle().SetMeshLocalPrefix(meshLocalPrefix.GetMeshLocalPrefix()); + mNetif.GetMac().SetExtendedPanId(extendedPanId.GetExtendedPanId()); + mNetif.GetMac().SetNetworkName(networkName.GetNetworkName()); + + otLogInfoMeshCoP("join success!\r\n"); + +exit: + (void)aMessageInfo; + return; +} + +void Joiner::Close(void) +{ + mNetif.GetDtls().Stop(); +} + +} // namespace Dtls +} // namespace Thread diff --git a/src/core/meshcop/joiner.hpp b/src/core/meshcop/joiner.hpp new file mode 100644 index 000000000..579583647 --- /dev/null +++ b/src/core/meshcop/joiner.hpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file includes definitions for the Joiner role. + */ + +#ifndef JOINER_HPP_ +#define JOINER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include + +namespace Thread { + +class ThreadNetif; + +namespace MeshCoP { + +class Joiner +{ +public: + /** + * This constructor initializes the Joiner object. + * + * @param[in] aThreadNetif A reference to the Thread network interface. + * + */ + Joiner(ThreadNetif &aThreadNetif); + + /** + * This method starts the Joiner service. + * + * @retval kThreadError_None Successfully started the Joiner service. + * + */ + ThreadError Start(void); + + /** + * This method stops the Joiner service. + * + * @retval kThreadError_None Successfully stopped the Joiner service. + * + */ + ThreadError Stop(void); + +private: + static void HandleDiscoverResult(otActiveScanResult *aResult, void *aContext); + void HandleDiscoverResult(otActiveScanResult *aResult); + + static void HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength); + void HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength); + + static ThreadError HandleDtlsSend(void *aContext, const uint8_t *aBuf, uint16_t aLength); + ThreadError HandleDtlsSend(const uint8_t *aBuf, uint16_t aLength); + + static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo); + void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + static void HandleUdpTransmit(void *aContext); + void HandleUdpTransmit(void); + + static void HandleJoinerEntrust(void *aContext, Coap::Header &aHeader, + Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + void HandleJoinerEntrust(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + void Close(void); + void ReceiveJoinerFinalizeResponse(uint8_t *buf, uint16_t length); + void SendJoinerFinalize(void); + + Mac::ExtAddress mJoinerRouter; + Message *mTransmitMessage; + Ip6::UdpSocket mSocket; + + Tasklet mTransmitTask; + Coap::Resource mJoinerEntrust; + ThreadNetif &mNetif; +}; + +} // namespace MeshCoP +} // namespace Thread + +#endif // JOINER_HPP_ diff --git a/src/core/meshcop/joiner_router.cpp b/src/core/meshcop/joiner_router.cpp new file mode 100644 index 000000000..350189d87 --- /dev/null +++ b/src/core/meshcop/joiner_router.cpp @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file implements the Joiner Router role. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using Thread::Encoding::BigEndian::HostSwap16; + +namespace Thread { +namespace MeshCoP { + +JoinerRouter::JoinerRouter(ThreadNetif &aNetif): + mJoinerPort(OPENTHREAD_CONFIG_JOINER_UDP_PORT), + mSocket(aNetif.GetIp6().mUdp), + mRelayTransmit(OPENTHREAD_URI_RELAY_TX, &HandleRelayTransmit, this), + mNetif(aNetif) +{ + mNetif.GetCoapServer().AddResource(mRelayTransmit); + mNetifCallback.Set(HandleNetifStateChanged, this); + mNetif.RegisterCallback(mNetifCallback); +} + +void JoinerRouter::HandleNetifStateChanged(uint32_t aFlags, void *aContext) +{ + static_cast(aContext)->HandleNetifStateChanged(aFlags); +} + +void JoinerRouter::HandleNetifStateChanged(uint32_t aFlags) +{ + uint8_t length; + + VerifyOrExit(mNetif.GetMle().GetDeviceMode() & Mle::ModeTlv::kModeFFD, ;); + VerifyOrExit(aFlags & OT_THREAD_NETDATA_UPDATED, ;); + + mNetif.GetIp6Filter().RemoveUnsecurePort(mJoinerPort); + + if (mNetif.GetNetworkDataLeader().GetCommissioningData(length) != NULL) + { + Ip6::SockAddr sockaddr; + + if (GetJoinerPort(mJoinerPort) != kThreadError_None) + { + mJoinerPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT; + } + + sockaddr.mPort = mJoinerPort; + mSocket.Open(&HandleUdpReceive, this); + mSocket.Bind(sockaddr); + mNetif.GetIp6Filter().AddUnsecurePort(sockaddr.mPort); + otLogInfoMeshCoP("Joiner Router: start\r\n"); + } + else + { + mSocket.Close(); + } + +exit: + return; +} + +ThreadError JoinerRouter::GetBorderAgentRloc(uint16_t &aRloc) +{ + ThreadError error = kThreadError_NotFound; + uint8_t *cur; + uint8_t *end; + uint8_t length; + + VerifyOrExit((cur = mNetif.GetNetworkDataLeader().GetCommissioningData(length)) != NULL, ;); + + end = cur + length; + + while (cur < end) + { + Tlv *tlv = reinterpret_cast(cur); + + if (tlv->GetType() == Tlv::kBorderAgentLocator) + { + aRloc = reinterpret_cast(tlv)->GetBorderAgentLocator(); + ExitNow(error = kThreadError_None); + } + + cur += sizeof(Tlv) + tlv->GetLength(); + } + +exit: + return error; +} + +ThreadError JoinerRouter::GetJoinerPort(uint16_t &aJoinerPort) +{ + ThreadError error = kThreadError_NotFound; + uint8_t *cur; + uint8_t *end; + uint8_t length; + + VerifyOrExit((cur = mNetif.GetNetworkDataLeader().GetCommissioningData(length)) != NULL, ;); + + end = cur + length; + + while (cur < end) + { + Tlv *tlv = reinterpret_cast(cur); + + if (tlv->GetType() == Tlv::kJoinerUdpPort) + { + aJoinerPort = reinterpret_cast(tlv)->GetUdpPort(); + ExitNow(error = kThreadError_None); + } + + cur += sizeof(Tlv) + tlv->GetLength(); + } + +exit: + return error; +} + +void JoinerRouter::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo) +{ + static_cast(aContext)->HandleUdpReceive(*static_cast(aMessage), + *static_cast(aMessageInfo)); +} + +void JoinerRouter::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + ThreadError error; + Message *message = NULL; + Coap::Header header; + Ip6::MessageInfo messageInfo; + JoinerUdpPortTlv udpPort; + JoinerIidTlv iid; + ExtendedTlv tlv; + uint16_t borderAgentRloc; + + otLogInfoMeshCoP("JoinerRouter::HandleUdpReceive\r\n"); + + SuccessOrExit(error = GetBorderAgentRloc(borderAgentRloc)); + + VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + + header.Init(); + header.SetVersion(1); + header.SetType(Coap::Header::kTypeNonConfirmable); + header.SetCode(Coap::Header::kCodePost); + header.SetMessageId(0); + header.SetToken(NULL, 0); + header.AppendUriPathOptions(OPENTHREAD_URI_RELAY_RX); + header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + header.Finalize(); + SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength())); + + udpPort.Init(); + udpPort.SetUdpPort(aMessageInfo.mPeerPort); + SuccessOrExit(error = message->Append(&udpPort, sizeof(udpPort))); + + iid.Init(); + iid.SetIid(aMessageInfo.GetPeerAddr().mFields.m8 + 8); + SuccessOrExit(error = message->Append(&iid, sizeof(iid))); + + tlv.SetType(Tlv::kJoinerDtlsEncapsulation); + tlv.SetLength(aMessage.GetLength() - aMessage.GetOffset()); + SuccessOrExit(error = message->Append(&tlv, sizeof(tlv))); + + while (aMessage.GetOffset() < aMessage.GetLength()) + { + uint16_t length = aMessage.GetLength() - aMessage.GetOffset(); + uint8_t tmp[16]; + + if (length >= sizeof(tmp)) + { + length = sizeof(tmp); + } + + aMessage.Read(aMessage.GetOffset(), length, tmp); + aMessage.MoveOffset(length); + + SuccessOrExit(error = message->Append(tmp, length)); + } + + memset(&messageInfo, 0, sizeof(messageInfo)); + memcpy(messageInfo.GetPeerAddr().mFields.m8, mNetif.GetMle().GetMeshLocalPrefix(), 8); + messageInfo.GetPeerAddr().mFields.m16[5] = HostSwap16(0x00ff); + messageInfo.GetPeerAddr().mFields.m16[6] = HostSwap16(0xfe00); + messageInfo.GetPeerAddr().mFields.m16[7] = HostSwap16(borderAgentRloc); + messageInfo.mPeerPort = kCoapUdpPort; + + SuccessOrExit(error = mSocket.SendTo(*message, messageInfo)); + + otLogInfoMeshCoP("Sent relay rx\r\n"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } +} + +void JoinerRouter::HandleRelayTransmit(void *aContext, Coap::Header &aHeader, + Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + static_cast(aContext)->HandleRelayTransmit(aHeader, aMessage, aMessageInfo); +} + +void JoinerRouter::HandleRelayTransmit(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + ThreadError error; + JoinerUdpPortTlv joinerPort; + JoinerIidTlv joinerIid; + JoinerRouterKekTlv kek; + uint16_t offset; + uint16_t length; + Message *message = NULL; + Ip6::MessageInfo messageInfo; + + VerifyOrExit(aHeader.GetType() == Coap::Header::kTypeNonConfirmable && + aHeader.GetCode() == Coap::Header::kCodePost, error = kThreadError_Drop); + + otLogInfoMeshCoP("Received relay transmit\r\n"); + + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kJoinerUdpPort, sizeof(joinerPort), joinerPort)); + VerifyOrExit(joinerPort.IsValid(), error = kThreadError_Parse); + + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kJoinerIid, sizeof(joinerIid), joinerIid)); + VerifyOrExit(joinerIid.IsValid(), error = kThreadError_Parse); + + SuccessOrExit(error = Tlv::GetValueOffset(aMessage, Tlv::kJoinerDtlsEncapsulation, offset, length)); + + VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + message->SetLinkSecurityEnabled(false); + + while (length) + { + uint16_t copyLength = length; + uint8_t tmp[16]; + + if (copyLength >= sizeof(tmp)) + { + copyLength = sizeof(tmp); + } + + aMessage.Read(offset, copyLength, tmp); + SuccessOrExit(error = message->Append(tmp, copyLength)); + + offset += copyLength; + length -= copyLength; + } + + aMessage.CopyTo(offset, 0, length, *message); + + memset(&messageInfo, 0, sizeof(messageInfo)); + messageInfo.mPeerAddr.mFields.m16[0] = HostSwap16(0xfe80); + memcpy(messageInfo.mPeerAddr.mFields.m8 + 8, joinerIid.GetIid(), 8); + messageInfo.mPeerPort = joinerPort.GetUdpPort(); + messageInfo.mInterfaceId = mNetif.GetInterfaceId(); + + SuccessOrExit(error = mSocket.SendTo(*message, messageInfo)); + + if (Tlv::GetTlv(aMessage, Tlv::kJoinerRouterKek, sizeof(kek), kek) == kThreadError_None) + { + otLogInfoMeshCoP("Received kek\r\n"); + mNetif.GetKeyManager().SetKek(kek.GetKek()); + SendJoinerEntrust(messageInfo); + } + +exit: + (void)aMessageInfo; + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } +} + +ThreadError JoinerRouter::SendJoinerEntrust(const Ip6::MessageInfo &aMessageInfo) +{ + ThreadError error; + Message *message = NULL; + Coap::Header header; + Ip6::MessageInfo messageInfo; + + NetworkMasterKeyTlv masterKey; + MeshLocalPrefixTlv meshLocalPrefix; + ExtendedPanIdTlv extendedPanId; + NetworkNameTlv networkName; + ActiveTimestampTlv activeTimestamp; + Tlv *tlv; + + VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + message->SetJoinerEntrust(true); + + header.Init(); + header.SetVersion(1); + header.SetType(Coap::Header::kTypeConfirmable); + header.SetCode(Coap::Header::kCodePost); + header.SetMessageId(0); + header.SetToken(NULL, 0); + header.AppendUriPathOptions(OPENTHREAD_URI_JOINER_ENTRUST); + header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + header.Finalize(); + SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength())); + + masterKey.Init(); + masterKey.SetNetworkMasterKey(mNetif.GetKeyManager().GetMasterKey(NULL)); + SuccessOrExit(error = message->Append(&masterKey, sizeof(masterKey))); + + meshLocalPrefix.Init(); + meshLocalPrefix.SetMeshLocalPrefix(mNetif.GetMle().GetMeshLocalPrefix()); + SuccessOrExit(error = message->Append(&meshLocalPrefix, sizeof(meshLocalPrefix))); + + extendedPanId.Init(); + extendedPanId.SetExtendedPanId(mNetif.GetMac().GetExtendedPanId()); + SuccessOrExit(error = message->Append(&extendedPanId, sizeof(extendedPanId))); + + networkName.Init(); + networkName.SetNetworkName(mNetif.GetMac().GetNetworkName()); + SuccessOrExit(error = message->Append(&networkName, sizeof(Tlv) + networkName.GetLength())); + + activeTimestamp.Init(); + *static_cast(&activeTimestamp) = mNetif.GetActiveDataset().GetNetwork().GetTimestamp(); + SuccessOrExit(error = message->Append(&activeTimestamp, sizeof(activeTimestamp))); + + if ((tlv = mNetif.GetActiveDataset().GetNetwork().Get(Tlv::kChannelMask)) != NULL) + { + SuccessOrExit(error = message->Append(tlv, sizeof(Tlv) + tlv->GetLength())); + } + else + { + ChannelMaskTlv channelMask; + channelMask.Init(); + SuccessOrExit(error = message->Append(&channelMask, sizeof(channelMask))); + } + + if ((tlv = mNetif.GetActiveDataset().GetNetwork().Get(Tlv::kPSKc)) != NULL) + { + SuccessOrExit(error = message->Append(tlv, sizeof(Tlv) + tlv->GetLength())); + } + else + { + PSKcTlv pskc; + pskc.Init(); + SuccessOrExit(error = message->Append(&pskc, sizeof(pskc))); + } + + if ((tlv = mNetif.GetActiveDataset().GetNetwork().Get(Tlv::kSecurityPolicy)) != NULL) + { + SuccessOrExit(error = message->Append(tlv, sizeof(Tlv) + tlv->GetLength())); + } + else + { + SecurityPolicyTlv securityPolicy; + securityPolicy.Init(); + SuccessOrExit(error = message->Append(&securityPolicy, sizeof(securityPolicy))); + } + + messageInfo = aMessageInfo; + messageInfo.mPeerPort = kCoapUdpPort; + SuccessOrExit(error = mSocket.SendTo(*message, messageInfo)); + + otLogInfoMeshCoP("Sent joiner entrust length = %d\r\n", message->GetLength()); + +exit: + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } + + return error; +} + +} // namespace Dtls +} // namespace Thread diff --git a/src/core/meshcop/joiner_router.hpp b/src/core/meshcop/joiner_router.hpp new file mode 100644 index 000000000..8613729ef --- /dev/null +++ b/src/core/meshcop/joiner_router.hpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file includes definitions for the Joiner Router role. + */ + +#ifndef JOINER_ROUTER_HPP_ +#define JOINER_ROUTER_HPP_ + +#include + +#include +#include +#include +#include +#include + +namespace Thread { + +class ThreadNetif; + +namespace MeshCoP { + +class JoinerRouter +{ +public: + /** + * This constructor initializes the Joiner Router object. + * + * @param[in] aThreadNetif A reference to the Thread network interface. + * + */ + JoinerRouter(ThreadNetif &aNetif); + +private: + static void HandleNetifStateChanged(uint32_t aFlags, void *aContext); + void HandleNetifStateChanged(uint32_t aFlags); + + static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo); + void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + static void HandleRelayTransmit(void *aContext, Coap::Header &aHeader, + Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + void HandleRelayTransmit(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + ThreadError SendJoinerEntrust(const Ip6::MessageInfo &aMessageInfo); + + ThreadError GetBorderAgentRloc(uint16_t &aRloc); + ThreadError GetJoinerPort(uint16_t &aRloc); + + Ip6::NetifCallback mNetifCallback; + uint16_t mJoinerPort; + + Ip6::UdpSocket mSocket; + Coap::Resource mRelayTransmit; + ThreadNetif &mNetif; +}; + +} // namespace MeshCoP +} // namespace Thread + +#endif // JOINER_ROUTER_HPP_ diff --git a/src/core/meshcop/leader.cpp b/src/core/meshcop/leader.cpp new file mode 100644 index 000000000..bd39a5479 --- /dev/null +++ b/src/core/meshcop/leader.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file implements a MeshCoP Leader. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Thread { +namespace MeshCoP { + +Leader::Leader(ThreadNetif &aThreadNetif): + mPetition(OPENTHREAD_URI_LEADER_PETITION, HandlePetition, this), + mKeepAlive(OPENTHREAD_URI_LEADER_KEEP_ALIVE, HandleKeepAlive, this), + mCoapServer(aThreadNetif.GetCoapServer()), + mNetworkData(aThreadNetif.GetNetworkDataLeader()), + mTimer(aThreadNetif.GetIp6().mTimerScheduler, HandleTimer, this) +{ + mCoapServer.AddResource(mPetition); + mCoapServer.AddResource(mKeepAlive); +} + +void Leader::HandlePetition(void *aContext, Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo) +{ + static_cast(aContext)->HandlePetition(aHeader, aMessage, aMessageInfo); +} + +void Leader::HandlePetition(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + CommissioningData data; + CommissionerIdTlv commissionerId; + StateTlv::State state = StateTlv::kReject; + + otLogInfoMeshCoP("received petition\r\n"); + + SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kCommissionerId, sizeof(commissionerId), commissionerId)); + + VerifyOrExit(!mTimer.IsRunning(), ;); + + data.mBorderAgentLocator.Init(); + data.mBorderAgentLocator.SetBorderAgentLocator(HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[7])); + + data.mCommissionerSessionId.Init(); + data.mCommissionerSessionId.SetCommissionerSessionId(++mSessionId); + + data.mSteeringData.Init(); + data.mSteeringData.SetLength(1); + data.mSteeringData.Clear(); + + SuccessOrExit(mNetworkData.SetCommissioningData(reinterpret_cast(&data), data.GetLength())); + + mCommissionerId = commissionerId; + + state = StateTlv::kAccept; + mTimer.Start(Timer::SecToMsec(kTimeoutLeaderPetition)); + +exit: + (void)aMessageInfo; + SendPetitionResponse(aHeader, aMessageInfo, state); +} + +ThreadError Leader::SendPetitionResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, + StateTlv::State aState) +{ + ThreadError error = kThreadError_None; + Coap::Header responseHeader; + StateTlv state; + CommissionerSessionIdTlv sessionId; + Message *message; + + VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + responseHeader.Init(); + responseHeader.SetVersion(1); + responseHeader.SetType(Coap::Header::kTypeAcknowledgment); + responseHeader.SetCode(Coap::Header::kCodeChanged); + responseHeader.SetMessageId(aRequestHeader.GetMessageId()); + responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength()); + responseHeader.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + responseHeader.Finalize(); + SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength())); + + state.Init(); + state.SetState(aState); + SuccessOrExit(error = message->Append(&state, sizeof(state))); + + if (mTimer.IsRunning()) + { + SuccessOrExit(error = message->Append(&mCommissionerId, sizeof(mCommissionerId))); + } + + if (aState == StateTlv::kAccept) + { + sessionId.Init(); + sessionId.SetCommissionerSessionId(mSessionId); + SuccessOrExit(error = message->Append(&sessionId, sizeof(sessionId))); + + } + + SuccessOrExit(error = mCoapServer.SendMessage(*message, aMessageInfo)); + + otLogInfoMeshCoP("sent petition response\r\n"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } + + return error; +} + +void Leader::HandleKeepAlive(void *aContext, Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo) +{ + static_cast(aContext)->HandleKeepAlive(aHeader, aMessage, aMessageInfo); +} + +void Leader::HandleKeepAlive(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + StateTlv state; + CommissionerSessionIdTlv sessionId; + StateTlv::State responseState; + + otLogInfoMeshCoP("received keep alive\r\n"); + + SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kState, sizeof(state), state)); + SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kCommissionerSessionId, sizeof(sessionId), sessionId)); + + if (sessionId.GetCommissionerSessionId() != mSessionId) + { + responseState = StateTlv::kReject; + } + else if (state.GetState() != StateTlv::kAccept) + { + responseState = StateTlv::kReject; + mTimer.Stop(); + mNetworkData.SetCommissioningData(NULL, 0); + otLogInfoMeshCoP("commissioner inactive\r\n"); + } + else + { + responseState = StateTlv::kAccept; + mTimer.Start(Timer::SecToMsec(kTimeoutLeaderPetition)); + } + + SendKeepAliveResponse(aHeader, aMessageInfo, responseState); + +exit: + return; +} + +ThreadError Leader::SendKeepAliveResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, + StateTlv::State aState) +{ + ThreadError error = kThreadError_None; + Coap::Header responseHeader; + StateTlv state; + Message *message; + + VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + responseHeader.Init(); + responseHeader.SetVersion(1); + responseHeader.SetType(Coap::Header::kTypeAcknowledgment); + responseHeader.SetCode(Coap::Header::kCodeChanged); + responseHeader.SetMessageId(aRequestHeader.GetMessageId()); + responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength()); + responseHeader.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + responseHeader.Finalize(); + SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength())); + + state.Init(); + state.SetState(aState); + SuccessOrExit(error = message->Append(&state, sizeof(state))); + + SuccessOrExit(error = mCoapServer.SendMessage(*message, aMessageInfo)); + + otLogInfoMeshCoP("sent keep alive response\r\n"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } + + return error; +} + +void Leader::HandleTimer(void *aContext) +{ + static_cast(aContext)->HandleTimer(); +} + +void Leader::HandleTimer(void) +{ + otLogInfoMeshCoP("commissioner inactive\r\n"); + mNetworkData.SetCommissioningData(NULL, 0); +} + +} // namespace MeshCoP +} // namespace Thread diff --git a/src/core/meshcop/leader.hpp b/src/core/meshcop/leader.hpp new file mode 100644 index 000000000..8de86252f --- /dev/null +++ b/src/core/meshcop/leader.hpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file includes definitions for a MeshCoP Leader. + */ + +#ifndef MESHCOP_LEADER_HPP_ +#define MESHCOP_LEADER_HPP_ + +#include +#include +#include +#include +#include + +namespace Thread { +namespace MeshCoP { + +OT_TOOL_PACKED_BEGIN +class CommissioningData +{ +public: + uint8_t GetLength(void) const { + return sizeof(Tlv) + mBorderAgentLocator.GetLength() + + sizeof(Tlv) + mCommissionerSessionId.GetLength() + + sizeof(Tlv) + mSteeringData.GetLength(); + } + + BorderAgentLocatorTlv mBorderAgentLocator; + CommissionerSessionIdTlv mCommissionerSessionId; + SteeringDataTlv mSteeringData; +} OT_TOOL_PACKED_END; + +class Leader +{ +public: + /** + * This constructor initializes the Leader object. + * + * @param[in] aThreadNetif A reference to the Thread network interface. + * + */ + Leader(ThreadNetif &aThreadNetif); + +private: + enum + { + kTimeoutLeaderPetition = 50, ///< TIMEOUT_LEAD_PET (seconds) + }; + + static void HandleTimer(void *aContext); + void HandleTimer(void); + + static void HandlePetition(void *aContext, Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo); + void HandlePetition(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + ThreadError SendPetitionResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, + StateTlv::State aState); + + static void HandleKeepAlive(void *aContext, Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo); + void HandleKeepAlive(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + ThreadError SendKeepAliveResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, + StateTlv::State aState); + + Coap::Resource mPetition; + Coap::Resource mKeepAlive; + Coap::Server &mCoapServer; + NetworkData::Leader &mNetworkData; + + Timer mTimer; + + CommissionerIdTlv mCommissionerId; + uint16_t mSessionId; +}; + +} // namespace MeshCoP +} // namespace Thread + +#endif // MESHCOP_LEADER_HPP_ diff --git a/src/core/openthread-core-default-config.h b/src/core/openthread-core-default-config.h index fe9e2479a..e41f3b6c4 100644 --- a/src/core/openthread-core-default-config.h +++ b/src/core/openthread-core-default-config.h @@ -155,6 +155,16 @@ #define OPENTHREAD_CONFIG_MPL_CACHE_ENTRY_LIFETIME 5 #endif // OPENTHREAD_CONFIG_MPL_CACHE_ENTRY_LIFETIME +/** + * @def OPENTHREAD_CONFIG_JOINER_UDP_PORT + * + * The MPL cache entry lifetime in seconds. + * + */ +#ifndef OPENTHREAD_CONFIG_JOINER_UDP_PORT +#define OPENTHREAD_CONFIG_JOINER_UDP_PORT 1000 +#endif // OPENTHREAD_CONFIG_JOINER_UDP_PORT + /** * @def OPENTHREAD_CONFIG_LOG_LEVEL * diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index 9e59aa2f3..e1979b918 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -875,9 +875,11 @@ ThreadError otEnable(void) VerifyOrExit(!mEnabled, error = kThreadError_InvalidState); otLogInfoApi("otEnable\n"); + new(&sMbedTlsRaw) Crypto::MbedTls; sIp6 = new(&sIp6Raw) Ip6::Ip6; sThreadNetif = new(&sThreadNetifRaw) ThreadNetif(*sIp6); + mEnabled = true; exit: @@ -1238,6 +1240,30 @@ ThreadError otSendPendingSet(const otOperationalDataset *aDataset, const uint8_t return sThreadNetif->GetPendingDataset().SendSetRequest(*aDataset, aTlvs, aLength); } +#if OPENTHREAD_ENABLE_COMMISSIONER +ThreadError otCommissionerStart(void) +{ + return sThreadNetif->GetCommissioner().Start(); +} + +ThreadError otCommissionerStop(void) +{ + return sThreadNetif->GetCommissioner().Stop(); +} +#endif // OPENTHREAD_ENABLE_COMMISSIONER + +#if OPENTHREAD_ENABLE_JOINER +ThreadError otJoinerStart(void) +{ + return sThreadNetif->GetJoiner().Start(); +} + +ThreadError otJoinerStop(void) +{ + return sThreadNetif->GetJoiner().Stop(); +} +#endif // OPENTHREAD_ENABLE_JOINER + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp index f832533e9..d38009a74 100644 --- a/src/core/thread/key_manager.cpp +++ b/src/core/thread/key_manager.cpp @@ -161,4 +161,25 @@ void KeyManager::IncrementMleFrameCounter(void) mMleFrameCounter++; } +const uint8_t *KeyManager::GetKek(void) const +{ + return mKek; +} + +void KeyManager::SetKek(const uint8_t *aKek) +{ + memcpy(mKek, aKek, sizeof(mKek)); + mKekFrameCounter = 0; +} + +uint32_t KeyManager::GetKekFrameCounter(void) const +{ + return mKekFrameCounter; +} + +void KeyManager::IncrementKekFrameCounter(void) +{ + mKekFrameCounter++; +} + } // namespace Thread diff --git a/src/core/thread/key_manager.hpp b/src/core/thread/key_manager.hpp index 901aa4e26..19b216fa6 100644 --- a/src/core/thread/key_manager.hpp +++ b/src/core/thread/key_manager.hpp @@ -148,8 +148,6 @@ public: /** * This method increments the current MAC Frame Counter value. * - * @returns The current MAC Frame Counter value. - * */ void IncrementMacFrameCounter(void); @@ -164,11 +162,39 @@ public: /** * This method increments the current MLE Frame Counter value. * - * @returns The current MLE Frame Counter value. - * */ void IncrementMleFrameCounter(void); + /** + * This method returns the KEK. + * + * @returns A pointer to the KEK. + * + */ + const uint8_t *GetKek(void) const; + + /** + * This method sets the KEK. + * + * @param[in] aKek A pointer to the KEK. + * + */ + void SetKek(const uint8_t *aKek); + + /** + * This method returns the current KEK Frame Counter value. + * + * @returns The current KEK Frame Counter value. + * + */ + uint32_t GetKekFrameCounter(void) const; + + /** + * This method increments the current KEK Frame Counter value. + * + */ + void IncrementKekFrameCounter(void); + private: enum { @@ -188,6 +214,9 @@ private: uint32_t mMacFrameCounter; uint32_t mMleFrameCounter; + uint8_t mKek[kMaxKeyLength]; + uint32_t mKekFrameCounter; + ThreadNetif &mNetif; }; diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index ad823db8a..51cee1d45 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -820,6 +820,7 @@ ThreadError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) int hcLength; uint16_t fragmentLength; uint16_t dstpan; + uint8_t secCtl = Mac::Frame::kSecNone; if (mAddMeshHeader) { @@ -848,6 +849,8 @@ ThreadError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) if (aMessage.IsLinkSecurityEnabled()) { fcf |= Mac::Frame::kFcfSecurityEnabled; + secCtl = aMessage.IsJoinerEntrust() ? Mac::Frame::kKeyIdMode0 : Mac::Frame::kKeyIdMode1; + secCtl |= Mac::Frame::kSecEncMic32; } if (aMessage.IsMleDiscoverRequest() || aMessage.IsMleDiscoverResponse()) @@ -864,7 +867,7 @@ ThreadError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) fcf |= Mac::Frame::kFcfPanidCompression; } - aFrame.InitMacHeader(fcf, Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecEncMic32); + aFrame.InitMacHeader(fcf, secCtl); aFrame.SetDstPanId(dstpan); aFrame.SetSrcPanId(mMac.GetPanId()); diff --git a/src/core/thread/meshcop_tlvs.cpp b/src/core/thread/meshcop_tlvs.cpp index 2b4ab8370..28982118a 100644 --- a/src/core/thread/meshcop_tlvs.cpp +++ b/src/core/thread/meshcop_tlvs.cpp @@ -69,5 +69,71 @@ int Timestamp::Compare(const Timestamp &aCompare) const return rval; } +ThreadError Tlv::GetTlv(const Message &message, Type type, uint16_t maxLength, Tlv &tlv) +{ + ThreadError error = kThreadError_Parse; + uint16_t offset = message.GetOffset(); + uint16_t end = message.GetLength(); + + while (offset < end) + { + message.Read(offset, sizeof(Tlv), &tlv); + + if (tlv.GetType() == type && (offset + sizeof(tlv) + tlv.GetLength()) <= end) + { + if (maxLength > sizeof(tlv) + tlv.GetLength()) + { + maxLength = sizeof(tlv) + tlv.GetLength(); + } + + message.Read(offset, maxLength, &tlv); + + ExitNow(error = kThreadError_None); + } + + offset += sizeof(tlv) + tlv.GetLength(); + } + +exit: + return error; +} + +ThreadError Tlv::GetValueOffset(const Message &aMessage, Type aType, uint16_t &aOffset, uint16_t &aLength) +{ + ThreadError error = kThreadError_Parse; + uint16_t offset = aMessage.GetOffset(); + uint16_t end = aMessage.GetLength(); + + while (offset < end) + { + Tlv tlv; + uint16_t length; + + aMessage.Read(offset, sizeof(tlv), &tlv); + offset += sizeof(tlv); + + length = tlv.GetLength(); + + if (length == kExtendedLength) + { + aMessage.Read(offset, sizeof(length), &length); + offset += sizeof(length); + length = HostSwap16(length); + } + + if (tlv.GetType() == aType) + { + aOffset = offset; + aLength = length; + ExitNow(error = kThreadError_None); + } + + offset += length; + } + +exit: + return error; +} + } // namespace MeshCoP } // namespace Thread diff --git a/src/core/thread/meshcop_tlvs.hpp b/src/core/thread/meshcop_tlvs.hpp index 227bebc6f..dcfb42146 100644 --- a/src/core/thread/meshcop_tlvs.hpp +++ b/src/core/thread/meshcop_tlvs.hpp @@ -39,6 +39,7 @@ #include #include +#include using Thread::Encoding::BigEndian::HostSwap16; using Thread::Encoding::BigEndian::HostSwap32; @@ -60,22 +61,39 @@ public: */ enum Type { - kChannel = OT_MESHCOP_TLV_CHANNEL, ///< Channel TLV - kPanId = OT_MESHCOP_TLV_PANID, ///< PAN ID TLV - kExtendedPanId = OT_MESHCOP_TLV_EXTPANID, ///< Extended PAN ID TLV - kNetworkName = OT_MESHCOP_TLV_NETWORKNAME, ///< Network Name TLV - kPSKc = OT_MESHCOP_TLV_PSKC, ///< PSKc TLV - kNetworkMasterKey = OT_MESHCOP_TLV_MASTERKEY, ///< Network Master Key TLV - kMeshLocalPrefix = OT_MESHCOP_TLV_LOCALPREFIX, ///< Mesh Local Prefix TLV - kSecurityPolicy = OT_MESHCOP_TLV_SECURITYPOLICY, ///< Security Policy TLV - kGet = OT_MESHCOP_TLV_GET, ///< Get TLV - kActiveTimestamp = OT_MESHCOP_TLV_ACTIVETIMESTAMP, ///< Active Timestamp TLV - kState = OT_MESHCOP_TLV_STATE, ///< State TLV - kPendingTimestamp = OT_MESHCOP_TLV_PENDINGTIMESTAMP, ///< Pending Timestamp TLV - kDelayTimer = OT_MESHCOP_TLV_DELAYTIMER, ///< Delay Timer TLV - kChannelMask = OT_MESHCOP_TLV_CHANNELMASK, ///< Channel Mask TLV - kDiscoveryRequest = OT_MESHCOP_TLV_DISCOVERYREQUEST, ///< Discovery Request TLV - kDiscoveryResponse = OT_MESHCOP_TLV_DISCOVERYRESPONSE, ///< Discovery Response TLV + kChannel = OT_MESHCOP_TLV_CHANNEL, ///< Channel TLV + kPanId = OT_MESHCOP_TLV_PANID, ///< PAN ID TLV + kExtendedPanId = OT_MESHCOP_TLV_EXTPANID, ///< Extended PAN ID TLV + kNetworkName = OT_MESHCOP_TLV_NETWORKNAME, ///< Newtork Name TLV + kPSKc = OT_MESHCOP_TLV_PSKC, ///< PSKc TLV + kNetworkMasterKey = OT_MESHCOP_TLV_MASTERKEY, ///< Network Master Key TLV + kMeshLocalPrefix = OT_MESHCOP_TLV_MESHLOCALPREFIX, ///< Mesh Local Prefix TLV + kSteeringData = OT_MESHCOP_TLV_STEERING_DATA, ///< Steering Data TLV + kBorderAgentLocator = OT_MESHCOP_TLV_BORDER_AGENT_RLOC, ///< Border Agent Locator TLV + kCommissionerId = OT_MESHCOP_TLV_COMMISSIONER_ID, ///< Commissioner ID TLV + kCommissionerSessionId = OT_MESHCOP_TLV_COMM_SESSION_ID, ///< Commissioner Session ID TLV + kSecurityPolicy = OT_MESHCOP_TLV_SECURITYPOLICY, ///< Security Policy TLV + kGet = OT_MESHCOP_TLV_GET, ///< Get TLV + kActiveTimestamp = OT_MESHCOP_TLV_ACTIVETIMESTAMP, ///< Active Timestamp TLV + kState = OT_MESHCOP_TLV_STATE, ///< State TLV + kJoinerDtlsEncapsulation = OT_MESHCOP_TLV_JOINER_DTLS, ///< Joiner DTLS Encapsulation TLV + kJoinerUdpPort = OT_MESHCOP_TLV_JOINER_UDP_PORT, ///< Joiner UDP Port TLV + kJoinerIid = OT_MESHCOP_TLV_JOINER_IID, ///< Joiner IID TLV + kJoinerRouterKek = OT_MESHCOP_TLV_JOINER_ROUTER_KEK, ///< Joiner Router KEK TLV + kPendingTimestamp = OT_MESHCOP_TLV_PENDINGTIMESTAMP, ///< Pending Timestamp TLV + kDelayTimer = OT_MESHCOP_TLV_DELAYTIMER, ///< Delay Timer TLV + kChannelMask = OT_MESHCOP_TLV_CHANNELMASK, ///< Channel Mask TLV + kDiscoveryRequest = OT_MESHCOP_TLV_DISCOVERYREQUEST, ///< Discovery Request TLV + kDiscoveryResponse = OT_MESHCOP_TLV_DISCOVERYRESPONSE, ///< Discovery Response TLV + }; + + /** + * Length values. + * + */ + enum + { + kExtendedLength = 255, ///< Extended Length value }; /** @@ -130,11 +148,61 @@ public: return reinterpret_cast(reinterpret_cast(this) + sizeof(*this) + mLength); } + /** + * This static method reads the requested TLV out of @p aMessage. + * + * @param[in] aMessage A reference to the message. + * @param[in] aType The Type value to search for. + * @param[in] aMaxLength Maximum number of bytes to read. + * @param[out] aTlv A reference to the TLV that will be copied to. + * + * @retval kThreadError_None Successfully copied the TLV. + * @retval kThreadError_NotFound Could not find the TLV with Type @p aType. + * + */ + static ThreadError GetTlv(const Message &aMessage, Type aType, uint16_t aMaxLength, Tlv &aTlv); + + /** + * This static method finds the offset and length of a given TLV type. + * + * @param[in] aMessage A reference to the message. + * @param[in] aType The Type value to search for. + * @param[out] aOffset The offset where the value starts. + * @param[out] aLength The length of the value. + * + * @retval kThreadError_None Successfully found the TLV. + * @retval kThreadError_NotFound Could not find the TLV with Type @p aType. + * + */ + static ThreadError GetValueOffset(const Message &aMesasge, Type aType, uint16_t &aOffset, uint16_t &aLength); + private: uint8_t mType; uint8_t mLength; } OT_TOOL_PACKED_END; +OT_TOOL_PACKED_BEGIN +class ExtendedTlv: public Tlv +{ +public: + /** + * This method returns the Length value. + * + */ + uint16_t GetLength() const { return HostSwap16(mLength); } + + /** + * This method sets the Length value. + * + * @param[in] aLength The Length value. + * + */ + void SetLength(uint16_t aLength) { Tlv::SetLength(kExtendedLength); mLength = HostSwap16(aLength); } + +private: + uint16_t mLength; +} OT_TOOL_PACKED_END; + /** * This class implements Channel TLV generation and parsing. * @@ -465,6 +533,206 @@ private: uint8_t mMeshLocalPrefix[8]; } OT_TOOL_PACKED_END; +/** + * This class implements Steering Data TLV generation and parsing. + * + */ +OT_TOOL_PACKED_BEGIN +class SteeringDataTlv: public Tlv +{ +public: + /** + * This method initializes the TLV. + * + */ + void Init(void) { SetType(kSteeringData); SetLength(sizeof(*this) - sizeof(Tlv)); Clear(); } + + /** + * This method indicates whether or not the TLV appears to be well-formed. + * + * @retval TRUE If the TLV appears to be well-formed. + * @retval FALSE If the TLV does not appear to be well-formed. + * + */ + bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); } + + /** + * This method sets all bits in the Bloom Filter to zero. + * + */ + void Clear(void) { memset(mSteeringData, 0, sizeof(mSteeringData)); } + + /** + * This method indicates whether or not bit @p aBit is set. + * + * @param[in] aBit The bit offset. + * + * @retval TRUE If bit @p aBit is set. + * @retval FALSE If bit @p aBit is not set. + * + */ + bool GetBit(uint8_t aBit) const { return (mSteeringData[aBit / 8] & (1 << (aBit % 8))) != 0; } + + /** + * This method clears bit @p aBit. + * + * @param[in] aBit The bit offset. + * + */ + void ClearBit(uint8_t aBit) { mSteeringData[aBit / 8] &= ~(1 << (aBit % 8)); } + + /** + * This method sets bit @p aBit. + * + * @param[in] aBit The bit offset. + * + */ + void SetBit(uint8_t aBit) { mSteeringData[aBit / 8] |= 1 << (aBit % 8); } + +private: + enum + { + kMaxLength = 16, + }; + uint8_t mSteeringData[kMaxLength]; +} OT_TOOL_PACKED_END; + +/** + * This class implements Border Agent Locator TLV generation and parsing. + * + */ +OT_TOOL_PACKED_BEGIN +class BorderAgentLocatorTlv: public Tlv +{ +public: + /** + * This method initializes the TLV. + * + */ + void Init(void) { SetType(kBorderAgentLocator); SetLength(sizeof(*this) - sizeof(Tlv)); } + + /** + * This method indicates whether or not the TLV appears to be well-formed. + * + * @retval TRUE If the TLV appears to be well-formed. + * @retval FALSE If the TLV does not appear to be well-formed. + * + */ + bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); } + + /** + * This method returns the Border Agent Locator value. + * + * @returns The Border Agent Locator value. + * + */ + uint16_t GetBorderAgentLocator(void) const { return HostSwap16(mLocator); } + + /** + * This method sets the Border Agent Locator value. + * + * @param[in] aBorderAgentLocator The Border Agent Locator value. + * + */ + void SetBorderAgentLocator(uint16_t aLocator) { mLocator = HostSwap16(aLocator); } + +private: + uint16_t mLocator; +} OT_TOOL_PACKED_END; + +/** + * This class implements the Commissioner ID TLV generation and parsing. + * + */ +class CommissionerIdTlv: public Tlv +{ +public: + /** + * This method initializes the TLV. + * + */ + void Init(void) { SetType(kCommissionerId); SetLength(sizeof(*this) - sizeof(Tlv)); } + + /** + * This method indicates whether or not the TLV appears to be well-formed. + * + * @retval TRUE If the TLV appears to be well-formed. + * @retval FALSE If the TLV does not appear to be well-formed. + * + */ + bool IsValid(void) const { return GetLength() <= sizeof(*this) - sizeof(Tlv); } + + /** + * This method returns the Commissioner ID value. + * + * @returns The Commissioner ID value. + * + */ + const char *GetCommissionerId(void) const { return mCommissionerId; } + + /** + * This method sets the Commissioner ID value. + * + * @param[in] aCommissionerId A pointer to the Commissioner ID value. + * + */ + void SetCommissionerId(const char *aCommissionerId) { + size_t length = strnlen(aCommissionerId, sizeof(mCommissionerId)); + memcpy(mCommissionerId, aCommissionerId, length); + } + +private: + enum + { + kMaxLength = 64, + }; + + char mCommissionerId[kMaxLength]; +} OT_TOOL_PACKED_END; + +/** + * This class implements Commissioner Session ID TLV generation and parsing. + * + */ +OT_TOOL_PACKED_BEGIN +class CommissionerSessionIdTlv: public Tlv +{ +public: + /** + * This method initializes the TLV. + * + */ + void Init(void) { SetType(kCommissionerSessionId); SetLength(sizeof(*this) - sizeof(Tlv)); } + + /** + * This method indicates whether or not the TLV appears to be well-formed. + * + * @retval TRUE If the TLV appears to be well-formed. + * @retval FALSE If the TLV does not appear to be well-formed. + * + */ + bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); } + + /** + * This method returns the Commissioner Session ID value. + * + * @returns The Commissioner Session ID value. + * + */ + uint16_t GetCommissionerSessionId(void) const { return HostSwap16(mSessionId); } + + /** + * This method sets the Commissioner Session ID value. + * + * @param[in] aCommissionerSessionId The Commissioner Session ID value. + * + */ + void SetCommissionerSessionId(uint16_t aSessionId) { mSessionId = HostSwap16(aSessionId); } + +private: + uint16_t mSessionId; +} OT_TOOL_PACKED_END; + /** * This class implements Security Policy TLV generation and parsing. * @@ -669,16 +937,6 @@ OT_TOOL_PACKED_BEGIN class StateTlv: public Tlv { public: - /** - * State TLV values. - */ - enum State - { - kReject = -1, ///< Reject - kPending = 0, ///< Pending - kAccept = 1, ///< Accept - }; - /** * This method initializes the TLV. * @@ -694,6 +952,17 @@ public: */ bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); } + /** + * State values. + * + */ + enum State + { + kReject = -1, ///< Reject + kPending = 0, ///< Pending + kAccept = 1, ///< Accept + }; + /** * This method returns the State value. * @@ -714,6 +983,135 @@ private: uint8_t mState; } OT_TOOL_PACKED_END; +/** + * This class implements Joiner UDP Port TLV generation and parsing. + * + */ +OT_TOOL_PACKED_BEGIN +class JoinerUdpPortTlv: public Tlv +{ +public: + /** + * This method initializes the TLV. + * + */ + void Init(void) { SetType(kJoinerUdpPort); SetLength(sizeof(*this) - sizeof(Tlv)); } + + /** + * This method indicates whether or not the TLV appears to be well-formed. + * + * @retval TRUE If the TLV appears to be well-formed. + * @retval FALSE If the TLV does not appear to be well-formed. + * + */ + bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); } + + /** + * This method returns the UDP Port value. + * + * @returns The UDP Port value. + * + */ + uint16_t GetUdpPort(void) const { return HostSwap16(mUdpPort); } + + /** + * This method sets the UDP Port value. + * + * @param[in] aUdpPort The UDP Port value. + * + */ + void SetUdpPort(uint16_t aUdpPort) { mUdpPort = HostSwap16(aUdpPort); } + +private: + uint16_t mUdpPort; +} OT_TOOL_PACKED_END; + +/** + * This class implements Joiner IID TLV generation and parsing. + * + */ +OT_TOOL_PACKED_BEGIN +class JoinerIidTlv: public Tlv +{ +public: + /** + * This method initializes the TLV. + * + */ + void Init() { SetType(kJoinerIid); SetLength(sizeof(*this) - sizeof(Tlv)); } + + /** + * This method indicates whether or not the TLV appears to be well-formed. + * + * @retval TRUE If the TLV appears to be well-formed. + * @retval FALSE If the TLV does not appear to be well-formed. + * + */ + bool IsValid() const { return GetLength() == sizeof(*this) - sizeof(Tlv); } + + /** + * This method returns a pointer to the Joiner IID. + * + * @returns A pointer to the Joiner IID. + * + */ + const uint8_t *GetIid() const { return mIid; } + + /** + * This method sets the Joiner IID. + * + * @param[in] aIid A pointer to the Joiner IID. + * + */ + void SetIid(const uint8_t *aIid) { memcpy(mIid, aIid, sizeof(mIid)); } + +private: + uint8_t mIid[8]; +} OT_TOOL_PACKED_END; + +/** + * This class implements Joiner Router KEK TLV generation and parsing. + * + */ +OT_TOOL_PACKED_BEGIN +class JoinerRouterKekTlv: public Tlv +{ +public: + /** + * This method initializes the TLV. + * + */ + void Init() { SetType(kJoinerRouterKek); SetLength(sizeof(*this) - sizeof(Tlv)); } + + /** + * This method indicates whether or not the TLV appears to be well-formed. + * + * @retval TRUE If the TLV appears to be well-formed. + * @retval FALSE If the TLV does not appear to be well-formed. + * + */ + bool IsValid() const { return GetLength() == sizeof(*this) - sizeof(Tlv); } + + /** + * This method returns a pointer to the Joiner Router KEK. + * + * @returns A pointer to the Joiner Router KEK. + * + */ + const uint8_t *GetKek() const { return mKek; } + + /** + * This method sets the Joiner Router KEK. + * + * @param[in] aIid A pointer to the Joiner Router KEK. + * + */ + void SetKek(const uint8_t *aKek) { memcpy(mKek, aKek, sizeof(mKek)); } + +private: + uint8_t mKek[16]; +} OT_TOOL_PACKED_END; + /** * This class implements Pending Timestamp TLV generation and parsing. * diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index 27b309779..aec811efe 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -460,6 +460,70 @@ exit: return; } +ThreadError Leader::SetCommissioningData(const uint8_t *aValue, uint8_t aValueLength) +{ + ThreadError error = kThreadError_None; + uint8_t remaining = kMaxSize - mLength; + CommissioningDataTlv *commissioningDataTlv; + + VerifyOrExit(sizeof(NetworkDataTlv) + aValueLength < remaining, error = kThreadError_NoBufs); + + RemoveCommissioningData(); + + if (aValueLength > 0) + { + commissioningDataTlv = reinterpret_cast(mTlvs + mLength); + Insert(reinterpret_cast(commissioningDataTlv), sizeof(CommissioningDataTlv) + aValueLength); + commissioningDataTlv->Init(); + commissioningDataTlv->SetLength(aValueLength); + memcpy(commissioningDataTlv->GetValue(), aValue, aValueLength); + } + + mVersion++; + mNetif.SetStateChangedFlags(OT_THREAD_NETDATA_UPDATED); + +exit: + return error; +} + +uint8_t *Leader::GetCommissioningData(uint8_t &aLength) +{ + uint8_t *rval = NULL; + + for (NetworkDataTlv *cur = reinterpret_cast(mTlvs); + cur < reinterpret_cast(mTlvs + mLength); + cur = cur->GetNext()) + { + if (cur->GetType() == NetworkDataTlv::kTypeCommissioningData) + { + aLength = cur->GetLength(); + ExitNow(rval = cur->GetValue()); + } + } + +exit: + return rval; +} + +ThreadError Leader::RemoveCommissioningData(void) +{ + ThreadError error = kThreadError_NotFound; + + for (NetworkDataTlv *cur = reinterpret_cast(mTlvs); + cur < reinterpret_cast(mTlvs + mLength); + cur = cur->GetNext()) + { + if (cur->GetType() == NetworkDataTlv::kTypeCommissioningData) + { + Remove(reinterpret_cast(cur), sizeof(NetworkDataTlv) + cur->GetLength()); + ExitNow(error = kThreadError_None); + } + } + +exit: + return error; +} + void Leader::HandleServerData(void *aContext, Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { diff --git a/src/core/thread/network_data_leader.hpp b/src/core/thread/network_data_leader.hpp index 9fa0a8a02..776276909 100644 --- a/src/core/thread/network_data_leader.hpp +++ b/src/core/thread/network_data_leader.hpp @@ -219,6 +219,28 @@ public: */ ThreadError SendServerDataNotification(uint16_t aRloc16); + /** + * This method returns a pointer to the Commissioning Data. + * + * @param[out] aLength The length of the Commissioning Data in bytes. + * + * @returns A pointer to the Commissioning Data or NULL if no Commissioning Data exists. + * + */ + uint8_t *GetCommissioningData(uint8_t &aLength); + + /** + * This method adds Commissioning Data to the Thread Network Data. + * + * @param[in] aValue A pointer to the Commissioning Data value. + * @param[in] aValueLength The length of @p aValue. + * + * @retval kThreadError_None Successfully added the Commissioning Data. + * @retval kThreadError_NoBufs Insufficient space to add the Commissioning Data. + * + */ + ThreadError SetCommissioningData(const uint8_t *aValue, uint8_t aValueLength); + private: static void HandleServerData(void *aContext, Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); @@ -245,6 +267,8 @@ private: ThreadError RemoveContext(uint8_t aContextId); ThreadError RemoveContext(PrefixTlv &aPrefix, uint8_t aContextId); + ThreadError RemoveCommissioningData(void); + ThreadError RemoveRloc(uint16_t aRloc16); ThreadError RemoveRloc(PrefixTlv &aPrefix, uint16_t aRloc16); ThreadError RemoveRloc(PrefixTlv &aPrefix, HasRouteTlv &aHasRoute, uint16_t aRloc16); diff --git a/src/core/thread/network_data_tlvs.hpp b/src/core/thread/network_data_tlvs.hpp index d5f3900d2..c3f9c3482 100644 --- a/src/core/thread/network_data_tlvs.hpp +++ b/src/core/thread/network_data_tlvs.hpp @@ -662,6 +662,21 @@ private: uint8_t mContextLength; } OT_TOOL_PACKED_END; +/** + * This class implements Commissioning Data TLV generation and parsing. + * + */ +OT_TOOL_PACKED_BEGIN +class CommissioningDataTlv: public NetworkDataTlv +{ +public: + /** + * This method initializes the TLV. + * + */ + void Init() { NetworkDataTlv::Init(); SetType(kTypeCommissioningData); SetLength(0); } +} OT_TOOL_PACKED_END; + /** * @} * diff --git a/src/core/thread/thread_netif.cpp b/src/core/thread/thread_netif.cpp index d8080510c..f88ad94f7 100644 --- a/src/core/thread/thread_netif.cpp +++ b/src/core/thread/thread_netif.cpp @@ -66,7 +66,18 @@ ThreadNetif::ThreadNetif(Ip6::Ip6 &aIp6): mMeshForwarder(*this), mMleRouter(*this), mNetworkDataLocal(*this), - mNetworkDataLeader(*this) + mNetworkDataLeader(*this), +#if OPENTHREAD_ENABLE_COMMISSIONER + mCommissioner(*this), +#endif // OPENTHREAD_ENABLE_COMMISSIONER +#if OPENTHREAD_ENABLE_DTLS + mDtls(*this), +#endif +#if OPENTHREAD_ENABLE_JOINER + mJoiner(*this), +#endif // OPENTHREAD_ENABLE_JOINER + mJoinerRouter(*this), + mLeader(*this) { mKeyManager.SetMasterKey(kThreadMasterKey, sizeof(kThreadMasterKey)); } diff --git a/src/core/thread/thread_netif.hpp b/src/core/thread/thread_netif.hpp index 11cfda6ff..6dc8674ee 100644 --- a/src/core/thread/thread_netif.hpp +++ b/src/core/thread/thread_netif.hpp @@ -34,8 +34,12 @@ #ifndef THREAD_NETIF_HPP_ #define THREAD_NETIF_HPP_ +#include #include + #include +#include +#include #include #include #include @@ -46,6 +50,18 @@ #include #include +#if OPENTHREAD_ENABLE_COMMISSIONER +#include +#endif // OPENTHREAD_ENABLE_COMMISSIONER + +#if OPENTHREAD_ENABLE_DTLS +#include +#endif // OPENTHREAD_ENABLE_DTLS + +#if OPENTHREAD_ENABLE_JOINER +#include +#endif // OPENTHREAD_ENABLE_JOINER + namespace Thread { /** @@ -212,6 +228,20 @@ public: MeshCoP::PendingDataset &GetPendingDataset(void) { return mPendingDataset; } + MeshCoP::JoinerRouter &GetJoinerRouter(void) { return mJoinerRouter; } + +#if OPENTHREAD_ENABLE_COMMISSIONER + MeshCoP::Commissioner &GetCommissioner(void) { return mCommissioner; } +#endif // OPENTHREAD_ENABLE_COMMISSIONER + +#if OPENTHREAD_ENABLE_DTLS + MeshCoP::Dtls &GetDtls(void) { return mDtls; } +#endif // OPENTHREAD_ENABLE_DTLS + +#if OPENTHREAD_ENABLE_JOINER + MeshCoP::Joiner &GetJoiner(void) { return mJoiner; } +#endif // OPENTHREAD_ENABLE_JOINER + private: Coap::Server mCoapServer; AddressResolver mAddressResolver; @@ -226,6 +256,21 @@ private: NetworkData::Local mNetworkDataLocal; NetworkData::Leader mNetworkDataLeader; bool mIsUp; + +#if OPENTHREAD_ENABLE_COMMISSIONER + MeshCoP::Commissioner mCommissioner; +#endif // OPENTHREAD_ENABLE_COMMISSIONER + +#if OPENTHREAD_ENABLE_DTLS + MeshCoP::Dtls mDtls; +#endif// OPENTHREAD_ENABLE_DTLS + +#if OPENTHREAD_ENABLE_JOINER + MeshCoP::Joiner mJoiner; +#endif // OPENTHREAD_ENABLE_JOINER + + MeshCoP::JoinerRouter mJoinerRouter; + MeshCoP::Leader mLeader; }; /** diff --git a/src/core/thread/thread_uris.hpp b/src/core/thread/thread_uris.hpp index 137beca6a..0032c3cb5 100644 --- a/src/core/thread/thread_uris.hpp +++ b/src/core/thread/thread_uris.hpp @@ -114,6 +114,54 @@ namespace Thread { */ #define OPENTHREAD_URI_SERVER_DATA "a/sd" +/** + * @def OPENTHREAD_URI_RELAY_RX + * + * The URI Path for Relay RX. + * + */ +#define OPENTHREAD_URI_RELAY_RX "c/rx" + +/** + * @def OPENTHREAD_URI_RELAY_TX + * + * The URI Path for Relay TX. + * + */ +#define OPENTHREAD_URI_RELAY_TX "c/tx" + +/** + * @def OPENTHREAD_URI_JOINER_FINALIZE + * + * The URI Path for Joiner Finalize + * + */ +#define OPENTHREAD_URI_JOINER_FINALIZE "c/jf" + +/** + * @def OPENTHREAD_URI_JOINER_ENTRUST + * + * The URI Path for Joiner Entrust + * + */ +#define OPENTHREAD_URI_JOINER_ENTRUST "c/je" + +/** + * @def OPENTHREAD_URI_LEADER_PETITION + * + * The URI Path for Leader Petition + * + */ +#define OPENTHREAD_URI_LEADER_PETITION "c/lp" + +/** + * @def OPENTHREAD_URI_LEADER_KEEP_ALIVE + * + * The URI Path for Leader Keep Alive + * + */ +#define OPENTHREAD_URI_LEADER_KEEP_ALIVE "c/la" + } // namespace Thread #endif // THREAD_URIS_HPP_ diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index d31a75e05..780c9e6fe 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -44,9 +45,7 @@ namespace Thread { -extern ThreadNetif *sThreadNetif; extern Ip6::Ip6 *sIp6; - static NcpBase *sNcpContext = NULL; #define NCP_PLAT_RESET_REASON (1U<<31) @@ -427,7 +426,6 @@ NcpBase::NcpBase(): mDroppedOutboundIpFrameCounter = 0; mDroppedInboundIpFrameCounter = 0; - assert(sThreadNetif != NULL); otSetStateChangedCallback(&HandleNetifStateChanged, this); otSetReceiveIp6DatagramCallback(&HandleDatagramFromStack, this); otSetIcmpEchoEnabled(false); diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index deb7f67f9..23b542bcd 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include "spinel.h" diff --git a/src/ncp/ncp_uart.cpp b/src/ncp/ncp_uart.cpp index e845333ae..f1c12b284 100644 --- a/src/ncp/ncp_uart.cpp +++ b/src/ncp/ncp_uart.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/third_party/mbedtls/Makefile.am b/third_party/mbedtls/Makefile.am index f49421701..96f15f588 100644 --- a/third_party/mbedtls/Makefile.am +++ b/third_party/mbedtls/Makefile.am @@ -27,6 +27,10 @@ lib_LIBRARIES = libmbedcrypto.a override CFLAGS := $(filter-out -Wconversion,$(CFLAGS)) override CXXFLAGS := $(filter-out -Wconversion,$(CXXFLAGS)) +# Do not enable -pedantic-errors for mbedtls +override CFLAGS := $(filter-out -pedantic-errors,$(CFLAGS)) +override CXXFLAGS := $(filter-out -pedantic-errors,$(CXXFLAGS)) + MBEDTLS_SRCDIR = $(top_srcdir)/third_party/mbedtls/repo libmbedcrypto_a_CPPFLAGS = \ @@ -46,6 +50,28 @@ libmbedcrypto_a_SOURCES = \ repo/library/sha256.c \ $(NULL) +if OPENTHREAD_ENABLE_DTLS +libmbedcrypto_a_SOURCES += \ + repo/library/bignum.c \ + repo/library/ccm.c \ + repo/library/cipher.c \ + repo/library/cipher_wrap.c \ + repo/library/ctr_drbg.c \ + repo/library/debug.c \ + repo/library/ecjpake.c \ + repo/library/ecp.c \ + repo/library/ecp_curves.c \ + repo/library/entropy.c \ + repo/library/entropy_poll.c \ + repo/library/ssl_cookie.c \ + repo/library/ssl_ciphersuites.c \ + repo/library/ssl_cli.c \ + repo/library/ssl_srv.c \ + repo/library/ssl_ticket.c \ + repo/library/ssl_tls.c \ + $(NULL) +endif # OPENTHREAD_ENABLE_DTLS + if OPENTHREAD_BUILD_COVERAGE CLEANFILES = $(wildcard *.gcda *.gcno) endif # OPENTHREAD_BUILD_COVERAGE diff --git a/third_party/mbedtls/mbedtls-config.h b/third_party/mbedtls/mbedtls-config.h index 817ce137c..495c2d90c 100644 --- a/third_party/mbedtls/mbedtls-config.h +++ b/third_party/mbedtls/mbedtls-config.h @@ -422,7 +422,7 @@ */ //#define MBEDTLS_ECP_DP_SECP192R1_ENABLED //#define MBEDTLS_ECP_DP_SECP224R1_ENABLED -//#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED //#define MBEDTLS_ECP_DP_SECP384R1_ENABLED //#define MBEDTLS_ECP_DP_SECP521R1_ENABLED //#define MBEDTLS_ECP_DP_SECP192K1_ENABLED @@ -442,7 +442,7 @@ * * Comment this macro to disable NIST curves optimisation. */ -//#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_ECP_NIST_OPTIM /** * \def MBEDTLS_ECDSA_DETERMINISTIC @@ -717,7 +717,7 @@ * enabled as well): * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 */ -//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED /** * \def MBEDTLS_PK_PARSE_EC_EXTENDED @@ -933,7 +933,7 @@ * a timing side-channel. * */ -//#define MBEDTLS_SSL_DEBUG_ALL +#define MBEDTLS_SSL_DEBUG_ALL /** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC * @@ -1052,7 +1052,7 @@ * * Comment this macro to disable support for the max_fragment_length extension */ -//#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH /** * \def MBEDTLS_SSL_PROTO_SSL3 @@ -1100,7 +1100,7 @@ * * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 */ -//#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_PROTO_TLS1_2 /** * \def MBEDTLS_SSL_PROTO_DTLS @@ -1115,7 +1115,7 @@ * * Comment this macro to disable support for DTLS */ -//#define MBEDTLS_SSL_PROTO_DTLS +#define MBEDTLS_SSL_PROTO_DTLS /** * \def MBEDTLS_SSL_ALPN @@ -1139,7 +1139,7 @@ * * Comment this to disable anti-replay in DTLS. */ -//#define MBEDTLS_SSL_DTLS_ANTI_REPLAY +#define MBEDTLS_SSL_DTLS_ANTI_REPLAY /** * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY @@ -1157,7 +1157,7 @@ * * Comment this to disable support for HelloVerifyRequest. */ -//#define MBEDTLS_SSL_DTLS_HELLO_VERIFY +#define MBEDTLS_SSL_DTLS_HELLO_VERIFY /** * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE @@ -1208,7 +1208,7 @@ * * Comment this macro to disable support for key export */ -//#define MBEDTLS_SSL_EXPORT_KEYS +#define MBEDTLS_SSL_EXPORT_KEYS /** * \def MBEDTLS_SSL_SERVER_NAME_INDICATION @@ -1478,7 +1478,7 @@ * library/pkcs5.c * library/pkparse.c */ -//#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_PARSE_C /** * \def MBEDTLS_ASN1_WRITE_C @@ -1492,7 +1492,7 @@ * library/x509write_crt.c * library/mbedtls_x509write_csr.c */ -//#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_ASN1_WRITE_C /** * \def MBEDTLS_BASE64_C @@ -1520,7 +1520,7 @@ * * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. */ -//#define MBEDTLS_BIGNUM_C +#define MBEDTLS_BIGNUM_C /** * \def MBEDTLS_BLOWFISH_C @@ -1598,7 +1598,7 @@ * This module enables the AES-CCM ciphersuites, if other requisites are * enabled as well. */ -//#define MBEDTLS_CCM_C +#define MBEDTLS_CCM_C /** * \def MBEDTLS_CERTS_C @@ -1636,7 +1636,7 @@ * * This module provides the CTR_DRBG AES-256 random number generator. */ -//#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_CTR_DRBG_C /** * \def MBEDTLS_DEBUG_C @@ -1650,7 +1650,7 @@ * * This module provides debugging functions. */ -//#define MBEDTLS_DEBUG_C +#define MBEDTLS_DEBUG_C /** * \def MBEDTLS_DES_C @@ -1740,7 +1740,7 @@ * * Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C */ -//#define MBEDTLS_ECJPAKE_C +#define MBEDTLS_ECJPAKE_C /** * \def MBEDTLS_ECP_C @@ -1754,7 +1754,7 @@ * * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED */ -//#define MBEDTLS_ECP_C +#define MBEDTLS_ECP_C /** * \def MBEDTLS_ENTROPY_C @@ -1768,7 +1768,7 @@ * * This module provides a generic entropy pool */ -//#define MBEDTLS_ENTROPY_C +#define MBEDTLS_ENTROPY_C /** * \def MBEDTLS_ERROR_C @@ -1831,7 +1831,7 @@ * * Uncomment to enable the HMAC_DRBG random number geerator. */ -//#define MBEDTLS_HMAC_DRBG_C +#define MBEDTLS_HMAC_DRBG_C /** * \def MBEDTLS_MD_C @@ -1940,7 +1940,7 @@ * * This modules translates between OIDs and internal values. */ -//#define MBEDTLS_OID_C +#define MBEDTLS_OID_C /** * \def MBEDTLS_PADLOCK_C @@ -2004,7 +2004,7 @@ * * Uncomment to enable generic public key wrappers. */ -//#define MBEDTLS_PK_C +#define MBEDTLS_PK_C /** * \def MBEDTLS_PK_PARSE_C @@ -2019,7 +2019,7 @@ * * Uncomment to enable generic public key parse functions. */ -//#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PK_PARSE_C /** * \def MBEDTLS_PK_WRITE_C @@ -2196,7 +2196,7 @@ * Module: library/ssl_cookie.c * Caller: */ -//#define MBEDTLS_SSL_COOKIE_C +#define MBEDTLS_SSL_COOKIE_C /** * \def MBEDTLS_SSL_TICKET_C @@ -2222,7 +2222,7 @@ * * This module is required for SSL/TLS client support. */ -//#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_CLI_C /** * \def MBEDTLS_SSL_SRV_C @@ -2236,7 +2236,7 @@ * * This module is required for SSL/TLS server support. */ -//#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_SRV_C /** * \def MBEDTLS_SSL_TLS_C @@ -2252,7 +2252,7 @@ * * This module is required for SSL/TLS. */ -//#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_SSL_TLS_C /** * \def MBEDTLS_THREADING_C @@ -2438,8 +2438,8 @@ */ /* MPI / BIGNUM options */ -//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ -//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ +#define MBEDTLS_MPI_WINDOW_SIZE 1 /**< Maximum windows size used. */ +#define MBEDTLS_MPI_MAX_SIZE 32 /**< Maximum number of bytes for usable MPIs. */ /* CTR_DRBG options */ //#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ @@ -2455,9 +2455,9 @@ //#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ /* ECP options */ -//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ -//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ -//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ +#define MBEDTLS_ECP_MAX_BITS 256 /**< Maximum bit size of groups */ +#define MBEDTLS_ECP_WINDOW_SIZE 2 /**< Maximum window size used */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Enable fixed-point speed-up */ /* Entropy options */ //#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ @@ -2496,7 +2496,7 @@ //#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ /* SSL options */ -//#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ +#define MBEDTLS_SSL_MAX_CONTENT_LEN 768 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ //#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ //#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ //#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ @@ -2513,7 +2513,7 @@ * * The value below is only an example, not the default. */ -//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 +#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 /* X509 options */ //#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */