mirror of
https://github.com/espressif/openthread.git
synced 2026-08-07 19:27:46 +00:00
[border-agent] introduce BorderAgent::EphemeralKeyManager (#11166)
This commit introduces the `BorderAgent::EphemeralKeyManager` class, which manages the use of the ephemeral key by the Border Agent. The `EphemeralKeyManager` uses its own DTLS transport and CoAP secure sessions. This allows the `EphemeralKeyManager` and the `BorderAgent` service (which uses PSKc) to be enabled and used in parallel. Previously, a single transport and session was shared between these functions, requiring the normal BA service (with PSKc) to be stopped before the ephemeral key could be used. This is a fundamental change and improvement to the ephemeral key and Border Agent functionality. Therefore some existing `otBorderAgent` APIs need to be modified. For example, `otBorderAgentGetState()`, which returned the Border Agent state to indicate whether there were any active sessions, is no longer meaningful, as different sessions/transports are now used for PSKc and ephemeral key, and there can be multiple sessions. This commit intentionally renames and changes the `otBorderAgent` public APIs, specifically all those related to ephemeral key use, to highlight the fundamental change in behavior. While this can cause backward incompatibility, it requires app layer code that used the previous APIs to be updated to take into account the new behavior. This commit also updates `nexus/test_border_agent`, adding new tests to validate the new behavior (e.g., BA service and ephemeral key parallel sessions). It also includes and validates the Border Agent counter updates under different scenarios (this enhances and replaces `test_ephemeral_key_counters.py`).
This commit is contained in:
+128
-130
@@ -55,26 +55,6 @@ extern "C" {
|
||||
*/
|
||||
#define OT_BORDER_AGENT_ID_LENGTH (16)
|
||||
|
||||
/**
|
||||
* Minimum length of the ephemeral key string.
|
||||
*/
|
||||
#define OT_BORDER_AGENT_MIN_EPHEMERAL_KEY_LENGTH (6)
|
||||
|
||||
/**
|
||||
* Maximum length of the ephemeral key string.
|
||||
*/
|
||||
#define OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_LENGTH (32)
|
||||
|
||||
/**
|
||||
* Default ephemeral key timeout interval in milliseconds.
|
||||
*/
|
||||
#define OT_BORDER_AGENT_DEFAULT_EPHEMERAL_KEY_TIMEOUT (2 * 60 * 1000u)
|
||||
|
||||
/**
|
||||
* Maximum ephemeral key timeout interval in milliseconds.
|
||||
*/
|
||||
#define OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT (10 * 60 * 1000u)
|
||||
|
||||
/**
|
||||
* Represents a Border Agent Identifier.
|
||||
*/
|
||||
@@ -84,15 +64,10 @@ typedef struct otBorderAgentId
|
||||
} otBorderAgentId;
|
||||
|
||||
/**
|
||||
* Defines the Border Agent state.
|
||||
* Defines Border Agent counters.
|
||||
*
|
||||
* The `mEpskc` related counters require `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
*/
|
||||
typedef enum otBorderAgentState
|
||||
{
|
||||
OT_BORDER_AGENT_STATE_STOPPED = 0, ///< Border agent role is disabled.
|
||||
OT_BORDER_AGENT_STATE_STARTED = 1, ///< Border agent is started.
|
||||
OT_BORDER_AGENT_STATE_ACTIVE = 2, ///< Border agent is connected with external commissioner.
|
||||
} otBorderAgentState;
|
||||
|
||||
typedef struct otBorderAgentCounters
|
||||
{
|
||||
uint32_t mEpskcActivations; ///< The number of ePSKc activations
|
||||
@@ -106,13 +81,11 @@ typedef struct otBorderAgentCounters
|
||||
uint32_t mEpskcSecureSessionSuccesses; ///< The number of established secure sessions with ePSKc
|
||||
uint32_t mEpskcSecureSessionFailures; ///< The number of failed secure sessions with ePSKc
|
||||
uint32_t mEpskcCommissionerPetitions; ///< The number of successful commissioner petitions with ePSKc
|
||||
|
||||
uint32_t mPskcSecureSessionSuccesses; ///< The number of established secure sessions with PSKc
|
||||
uint32_t mPskcSecureSessionFailures; ///< The number of failed secure sessions with PSKc
|
||||
uint32_t mPskcCommissionerPetitions; ///< The number of successful commissioner petitions with PSKc
|
||||
|
||||
uint32_t mMgmtActiveGets; ///< The number of MGMT_ACTIVE_GET.req sent over secure sessions
|
||||
uint32_t mMgmtPendingGets; ///< The number of MGMT_PENDING_GET.req sent over secure sessions
|
||||
uint32_t mPskcSecureSessionSuccesses; ///< The number of established secure sessions with PSKc
|
||||
uint32_t mPskcSecureSessionFailures; ///< The number of failed secure sessions with PSKc
|
||||
uint32_t mPskcCommissionerPetitions; ///< The number of successful commissioner petitions with PSKc
|
||||
uint32_t mMgmtActiveGets; ///< The number of MGMT_ACTIVE_GET.req sent over secure sessions
|
||||
uint32_t mMgmtPendingGets; ///< The number of MGMT_PENDING_GET.req sent over secure sessions
|
||||
} otBorderAgentCounters;
|
||||
|
||||
/**
|
||||
@@ -125,13 +98,21 @@ typedef struct otBorderAgentCounters
|
||||
const otBorderAgentCounters *otBorderAgentGetCounters(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Gets the #otBorderAgentState of the Thread Border Agent role.
|
||||
* Indicates whether or not the Border Agent service is active and running.
|
||||
*
|
||||
* While the Border Agent is active, external commissioner candidates can try to connect to and establish secure DTLS
|
||||
* sessions with the Border Agent using PSKc. A connected commissioner can then petition to become a full commissioner.
|
||||
*
|
||||
* If `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE` is enabled, independent and separate DTLS transport and
|
||||
* sessions are used for the ephemeral key. Therefore, the ephemeral key and Border Agent service can be enabled and
|
||||
* used in parallel.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* @returns The current #otBorderAgentState of the Border Agent.
|
||||
* @retval TRUE The Border Agent is active.
|
||||
* @retval FALSE The Border Agent is not active.
|
||||
*/
|
||||
otBorderAgentState otBorderAgentGetState(otInstance *aInstance);
|
||||
bool otBorderAgentIsActive(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Gets the UDP port of the Thread Border Agent service.
|
||||
@@ -180,117 +161,138 @@ otError otBorderAgentGetId(otInstance *aInstance, otBorderAgentId *aId);
|
||||
*/
|
||||
otError otBorderAgentSetId(otInstance *aInstance, const otBorderAgentId *aId);
|
||||
|
||||
/**
|
||||
* Indicates whether the Border Agent Ephemeral Key feature is enabled.
|
||||
*
|
||||
* The Ephemeral Key feature can only be used when it's enabled. This information will be displayed in a bitmap in the
|
||||
* txt records of the meshcop service published by this Border Router.
|
||||
*
|
||||
* The default value is `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_FEATURE_ENABLED_BY_DEFAULT`.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
*/
|
||||
bool otBorderAgentIsEphemeralKeyFeatureEnabled(otInstance *aInstance);
|
||||
/*--------------------------------------------------------------------------------------------------------------------
|
||||
* Border Agent Ephemeral Key feature */
|
||||
|
||||
/**
|
||||
* Enables/disables the Border Agent Ephemeral Key feature.
|
||||
*
|
||||
* If an ephemeral key is already active and then this method is called to disable the feature, the in-use ephemeral
|
||||
* key will be cleared.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aEnabled Whether to enable the BA Ephemeral Key feature.
|
||||
* Minimum length of the ephemeral key string.
|
||||
*/
|
||||
void otBorderAgentSetEphemeralKeyFeatureEnabled(otInstance *aInstance, bool aEnabled);
|
||||
#define OT_BORDER_AGENT_MIN_EPHEMERAL_KEY_LENGTH (6)
|
||||
|
||||
/**
|
||||
* Sets the ephemeral key for a given timeout duration.
|
||||
* Maximum length of the ephemeral key string.
|
||||
*/
|
||||
#define OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_LENGTH (32)
|
||||
|
||||
/**
|
||||
* Default ephemeral key timeout interval in milliseconds.
|
||||
*/
|
||||
#define OT_BORDER_AGENT_DEFAULT_EPHEMERAL_KEY_TIMEOUT (2 * 60 * 1000u)
|
||||
|
||||
/**
|
||||
* Maximum ephemeral key timeout interval in milliseconds.
|
||||
*/
|
||||
#define OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT (10 * 60 * 1000u)
|
||||
|
||||
/**
|
||||
* Represents Border Agent's Ephemeral Key Manager state.
|
||||
*/
|
||||
typedef enum otBorderAgentEphemeralKeyState
|
||||
{
|
||||
OT_BORDER_AGENT_STATE_DISABLED = 0, ///< Ephemeral Key Manager is disabled.
|
||||
OT_BORDER_AGENT_STATE_STOPPED = 1, ///< Enabled, but no ephemeral key is in use (not set or started).
|
||||
OT_BORDER_AGENT_STATE_STARTED = 2, ///< Ephemeral key is set. Listening to accept secure connections.
|
||||
OT_BORDER_AGENT_STATE_CONNECTED = 3, ///< Session is established with an external commissioner candidate.
|
||||
OT_BORDER_AGENT_STATE_ACCEPTED = 4, ///< Session is established and candidate is accepted as full commissioner.
|
||||
} otBorderAgentEphemeralKeyState;
|
||||
|
||||
/**
|
||||
* Gets the state of Border Agent's Ephemeral Key Manager.
|
||||
*
|
||||
* Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
*
|
||||
* The API SHOULD only be called when the Ephemeral Key feature is enabled (which can be set by
|
||||
* `otBorderAgentSetEphemeralKeyFeatureEnabled`) or configured as enabled by default.
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* The ephemeral key can be set when the Border Agent is already running and is not currently connected to any external
|
||||
* commissioner (i.e., it is in `OT_BORDER_AGENT_STATE_STARTED` state). Otherwise `OT_ERROR_INVALID_STATE` is returned.
|
||||
* To terminate active commissioner sessions, use the `otBorderAgentDisconnect()` API.
|
||||
*
|
||||
* The given @p aKeyString is directly used as the ephemeral PSK (excluding the trailing null `\0` character ).
|
||||
* The @p aKeyString length must be between `OT_BORDER_AGENT_MIN_EPHEMERAL_KEY_LENGTH` and
|
||||
* `OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_LENGTH`, inclusive.
|
||||
*
|
||||
* Setting the ephemeral key again before a previously set key has timed out will replace the previously set key and
|
||||
* reset the timeout.
|
||||
*
|
||||
* During the timeout interval, the ephemeral key can be used only once by an external commissioner to establish a
|
||||
* connection. After the commissioner disconnects, the ephemeral key is cleared, and the Border Agent reverts to
|
||||
* using PSKc. If the timeout expires while a commissioner is still connected, the session will be terminated, and the
|
||||
* Border Agent will cease using the ephemeral key and revert to PSKc.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aKeyString The ephemeral key string (used as PSK excluding the trailing null `\0` character).
|
||||
* @param[in] aTimeout The timeout duration in milliseconds to use the ephemeral key.
|
||||
* If zero, the default `OT_BORDER_AGENT_DEFAULT_EPHEMERAL_KEY_TIMEOUT` value will be used.
|
||||
* If the given timeout value is larger than `OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT`, the
|
||||
* max value `OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT` will be used instead.
|
||||
* @param[in] aUdpPort The UDP port to use with ephemeral key. If zero, an ephemeral port will be used.
|
||||
* `otBorderAgentGetUdpPort()` will return the current UDP port being used.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the ephemeral key.
|
||||
* @retval OT_ERROR_INVALID_STATE Border Agent is not running or it is connected to an external commissioner.
|
||||
* @retval OT_ERROR_INVALID_ARGS The given @p aKeyString is not valid (too short or too long).
|
||||
* @retval OT_ERROR_NOT_CAPABLE The Ephemeral Key feature is not enabled.
|
||||
* @retval OT_ERROR_FAILED Failed to set the key (e.g., could not bind to UDP port).
|
||||
* @returns The current state of Ephemeral Key Manager.
|
||||
*/
|
||||
otError otBorderAgentSetEphemeralKey(otInstance *aInstance,
|
||||
const char *aKeyString,
|
||||
uint32_t aTimeout,
|
||||
uint16_t aUdpPort);
|
||||
otBorderAgentEphemeralKeyState otBorderAgentEphemeralKeyGetState(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Cancels the ephemeral key that is in use.
|
||||
* Enables/disables the Border Agent's Ephemeral Key Manager.
|
||||
*
|
||||
* Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
*
|
||||
* Can be used to cancel a previously set ephemeral key before it times out. If the Border Agent is not running or
|
||||
* there is no ephemeral key in use, calling this function has no effect.
|
||||
*
|
||||
* If a commissioner is connected using the ephemeral key and is currently active, calling this function does not
|
||||
* change its state. In this case the `otBorderAgentIsEphemeralKeyActive()` will continue to return `TRUE` until the
|
||||
* commissioner disconnects, or the ephemeral key timeout expires. To terminate active commissioner sessions, use the
|
||||
* `otBorderAgentDisconnect()` API.
|
||||
* If this function is called to disable, while an an ephemeral key is in use, the ephemeral key use will be stopped
|
||||
* (as if `otBorderAgentEphemeralKeyStop()` is called).
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aEnabled Whether to enable or disable the Ephemeral Key Manager.
|
||||
*/
|
||||
void otBorderAgentClearEphemeralKey(otInstance *aInstance);
|
||||
void otBorderAgentEphemeralKeySetEnabled(otInstance *aInstance, bool aEnabled);
|
||||
|
||||
/**
|
||||
* Indicates whether or not an ephemeral key is currently active.
|
||||
* Starts using an ephemeral key for a given timeout duration.
|
||||
*
|
||||
* Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* An ephemeral key can only be set when `otBorderAgentEphemeralKeyGetState()` is `OT_BORDER_AGENT_STATE_STOPPED`,
|
||||
* i.e., enabled but not yet started. Otherwise, `OT_ERROR_INVALID_STATE` is returned. This means that setting the
|
||||
* ephemeral key again while a previously set key is still in use will fail. Callers can stop the previous key by
|
||||
* calling `otBorderAgentEphemeralKeyStop()` before starting with a new key.
|
||||
*
|
||||
* @retval TRUE An ephemeral key is active.
|
||||
* @retval FALSE No ephemeral key is active.
|
||||
* The Ephemeral Key Manager and the Border Agent service (which uses PSKc) can be enabled and used in parallel, as
|
||||
* they use independent and separate DTLS transport and sessions.
|
||||
*
|
||||
* The given @p aKeyString is used directly as the ephemeral PSK (excluding the trailing null `\0` character).
|
||||
* Its length must be between `OT_BORDER_AGENT_MIN_EPHEMERAL_KEY_LENGTH` and `OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_LENGTH`,
|
||||
* inclusive. Otherwise `OT_ERROR_INVALID_ARGS` is returned.
|
||||
*
|
||||
* When successfully set, the ephemeral key can be used only once by an external commissioner candidate to establish a
|
||||
* secure session. After the commissioner candidate disconnects, the use of the ephemeral key is stopped. If the
|
||||
* timeout expires, the use of the ephemeral key is stopped, and any connected session using the key is immediately
|
||||
* disconnected.
|
||||
*
|
||||
* The Ephemeral Key Manager limits the number of failed DTLS connections to 10 attempts. After the 10th failed
|
||||
* attempt, the use of the ephemeral key is automatically stopped (even if the timeout has not yet expired).
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aKeyString The ephemeral key.
|
||||
* @param[in] aTimeout The timeout duration, in milliseconds, to use the ephemeral key.
|
||||
* If zero, the default `OT_BORDER_AGENT_DEFAULT_EPHEMERAL_KEY_TIMEOUT` value is used. If the
|
||||
* timeout value is larger than `OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT`, the maximum value
|
||||
* is used instead.
|
||||
* @param[in] aUdpPort The UDP port to use with the ephemeral key. If the UDP port is zero, an ephemeral port will
|
||||
* be used. `otBorderAgentEphemeralKeyGetUdpPort()` returns the current UDP port being used.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully started using the ephemeral key.
|
||||
* @retval OT_ERROR_INVALID_STATE A previously set ephemeral key is still in use or the feature is disabled.
|
||||
* @retval OT_ERROR_INVALID_ARGS The given @p aKeyString is not valid.
|
||||
* @retval OT_ERROR_FAILED Failed to start (e.g., it could not bind to the given UDP port).
|
||||
*/
|
||||
bool otBorderAgentIsEphemeralKeyActive(otInstance *aInstance);
|
||||
otError otBorderAgentEphemeralKeyStart(otInstance *aInstance,
|
||||
const char *aKeyString,
|
||||
uint32_t aTimeout,
|
||||
uint16_t aUdpPort);
|
||||
|
||||
/**
|
||||
* Callback function pointer to signal changes related to the Border Agent's ephemeral key.
|
||||
* Stops the ephemeral key use and disconnects any session using it.
|
||||
*
|
||||
* This callback is invoked whenever:
|
||||
* Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
*
|
||||
* - The Border Agent starts using an ephemeral key.
|
||||
* - Any parameter related to the ephemeral key, such as the port number, changes.
|
||||
* - A commissioner candidate successfully establishes a secure session with the Border Agent using the ephemeral key.
|
||||
* This situation can be identified by `otBorderAgentGetState()` being `OT_BORDER_AGENT_STATE_ACTIVE` (this event
|
||||
* can be used to stop advertising the mDNS service "_meshcop-e._udp").
|
||||
* - The Border Agent stops using the ephemeral key due to:
|
||||
* - A direct call to `otBorderAgentClearEphemeralKey()`.
|
||||
* - The ephemeral key timing out.
|
||||
* - An external commissioner successfully using the key to connect and then disconnecting.
|
||||
* - Reaching the maximum number of allowed failed connection attempts.
|
||||
* If there is no ephemeral key in use, calling this function has no effect.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
*/
|
||||
void otBorderAgentEphemeralKeyStop(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Gets the UDP port used by Border Agent's Ephemeral Key Manager.
|
||||
*
|
||||
* Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
*
|
||||
* The port is applicable if an ephemeral key is in use, i.e., the state is not `OT_BORDER_AGENT_STATE_DISABLED` or
|
||||
* `OT_BORDER_AGENT_STATE_STOPPED`.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* @returns The UDP port being used by Border Agent's Ephemeral Key Manager (when active).
|
||||
*/
|
||||
uint16_t otBorderAgentEphemeralKeyGetUdpPort(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Callback function pointer to signal state changes to the Border Agent's Ephemeral Key Manager.
|
||||
*
|
||||
* This callback is invoked whenever the `otBorderAgentEphemeralKeyGetState()` gets changed.
|
||||
*
|
||||
* Any OpenThread API, including `otBorderAgent` APIs, can be safely called from this callback.
|
||||
*
|
||||
@@ -299,7 +301,7 @@ bool otBorderAgentIsEphemeralKeyActive(otInstance *aInstance);
|
||||
typedef void (*otBorderAgentEphemeralKeyCallback)(void *aContext);
|
||||
|
||||
/**
|
||||
* Sets the callback function used by the Border Agent to notify any changes related to use of ephemeral key.
|
||||
* Sets the callback function to notify state changes of Border Agent's Ephemeral Key Manager.
|
||||
*
|
||||
* Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
*
|
||||
@@ -309,22 +311,18 @@ typedef void (*otBorderAgentEphemeralKeyCallback)(void *aContext);
|
||||
* @param[in] aCallback The callback function pointer.
|
||||
* @param[in] aContext The arbitrary context to use with callback.
|
||||
*/
|
||||
void otBorderAgentSetEphemeralKeyCallback(otInstance *aInstance,
|
||||
void otBorderAgentEphemeralKeySetCallback(otInstance *aInstance,
|
||||
otBorderAgentEphemeralKeyCallback aCallback,
|
||||
void *aContext);
|
||||
|
||||
/**
|
||||
* Disconnects the Border Agent from any active secure sessions.
|
||||
* Converts a given `otBorderAgentEphemeralKeyState` to a human-readable string.
|
||||
*
|
||||
* If Border Agent is connected to a commissioner candidate with ephemeral key, calling this API
|
||||
* will cause the ephemeral key to be cleared after the session is disconnected.
|
||||
* @param[in] aState The state to convert.
|
||||
*
|
||||
* The Border Agent state may not change immediately upon calling this method. The state will be
|
||||
* updated when the connection update is notified with a delay.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @returns Human-readable string corresponding to @p aState.
|
||||
*/
|
||||
void otBorderAgentDisconnect(otInstance *aInstance);
|
||||
const char *otBorderAgentEphemeralKeyStateToString(otBorderAgentEphemeralKeyState aState);
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (474)
|
||||
#define OPENTHREAD_API_VERSION (475)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
+92
-71
@@ -364,7 +364,7 @@ Show current Border Agent information.
|
||||
|
||||
### ba port
|
||||
|
||||
Print border agent service port.
|
||||
Print Border Agent's service port.
|
||||
|
||||
```bash
|
||||
> ba port
|
||||
@@ -374,138 +374,159 @@ Done
|
||||
|
||||
### ba state
|
||||
|
||||
Print border agent state.
|
||||
Print Border Agent's state.
|
||||
|
||||
Possible states are
|
||||
|
||||
- `Stopped` : Border Agent is stopped.
|
||||
- `Started` : Border Agent is running with no active connection with external commissioner.
|
||||
- `Active` : Border Agent is running and is connected with an external commissioner.
|
||||
- `Active`: Border Agent is active.
|
||||
- `Inactive`: Border Agent is not active.
|
||||
|
||||
```bash
|
||||
> ba state
|
||||
Started
|
||||
Done
|
||||
```
|
||||
|
||||
### ba disconnect
|
||||
|
||||
Disconnects border agent from any active secure sessions.
|
||||
|
||||
```bash
|
||||
> ba disconnect
|
||||
Active
|
||||
Done
|
||||
```
|
||||
|
||||
### ba ephemeralkey
|
||||
|
||||
Indicates if an ephemeral key is active.
|
||||
Print the Border Agent's Ephemeral Key Manager state.
|
||||
|
||||
Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
|
||||
Possible states are
|
||||
|
||||
- `Disabled`: Ephemeral Key Manager is disabled.
|
||||
- `Stopped`: Enabled but no key is in use (not yet set or started).
|
||||
- `Started`: Ephemeral key is set. Listening to accept secure connections from commissioner candidates.
|
||||
- `Connected`: Secure session is established with an external commissioner candidate. Not yet accepted as full commissioner.
|
||||
- `Accepted`: Secure session is established and external candidate is accepted as full commissioner.
|
||||
|
||||
```bash
|
||||
> ba ephemeralkey
|
||||
Stopped
|
||||
Done
|
||||
|
||||
> ba ephemeralkey start Z10X20g3J15w1000P60m16 1000
|
||||
Done
|
||||
|
||||
> ba ephemeralkey
|
||||
Started
|
||||
Done
|
||||
```
|
||||
|
||||
### ba ephemeralkey enable
|
||||
|
||||
Enables the Border agent's Ephemeral Key Manager.
|
||||
|
||||
Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
|
||||
```bash
|
||||
> ba ephemeralkey
|
||||
inactive
|
||||
Done
|
||||
|
||||
> ba ephemeralkey set Z10X20g3J15w1000P60m16 1000
|
||||
Done
|
||||
|
||||
> ba ephemeralkey
|
||||
active
|
||||
> ba ephemeralkey enable
|
||||
Done
|
||||
```
|
||||
|
||||
### ba ephemeralkey set \<keystring\> \[timeout\] \[port\]
|
||||
### ba ephemeralkey disable
|
||||
|
||||
Sets the ephemeral key for a given timeout duration.
|
||||
Disables the Border Agent's Ephemeral Key Manager.
|
||||
|
||||
Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
|
||||
The ephemeral key can be set when Border Agent is already running and is not currently connected to any external commissioner (i.e., `ba state` gives `Started`).
|
||||
```bash
|
||||
> ba ephemeralkey disable
|
||||
Done
|
||||
|
||||
> ba ephemeralkey
|
||||
Disabled
|
||||
Done
|
||||
```
|
||||
|
||||
### ba ephemeralkey start \<keystring\> \[timeout\] \[port\]
|
||||
|
||||
Starts using an ephemeral key for a given timeout duration.
|
||||
|
||||
Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
|
||||
An ephemeral key can only be set when current state is `Stopped`, i.e., it is enabled but not yet started. This means that setting the ephemeral key again while a previously set key is still in use will fail. Callers can stop the previous key using `ba ephemeralkey stop` before starting with a new key.
|
||||
|
||||
The Ephemeral Key Manager and the Border Agent service (which uses PSKc) can be enabled and used in parallel, as they use independent and separate DTLS transport and sessions.
|
||||
|
||||
The `keystring` string is directly used as the ephemeral PSK (excluding the trailing null `\0` character). Its length MUST be between 6 and 32, inclusive.
|
||||
|
||||
The `timeout` is in milliseconds. If not provided or set to zero, the default value of 2 minutes will be used. If the timeout value is larger than 10 minutes, the 10 minutes timeout value will be used instead.
|
||||
|
||||
The `port` specifies the UDP port to use with the ephemeral key. If UDP port is zero or is not provided, an ephemeral port will be used. `ba port` will give the current UDP port in use by the Border Agent.
|
||||
The `port` specifies the UDP port to use with the ephemeral key. If UDP port is zero or is not provided, an ephemeral port will be used. `ba ephemeralkey port` will give the current UDP port in use.
|
||||
|
||||
Setting the ephemeral key again before a previously set one is timed out, will replace the previous one.
|
||||
When successfully set, the ephemeral key can be used only once by an external commissioner candidate to establish a secure session. After the commissioner candidate disconnects, the use of the ephemeral key is stopped. If the timeout expires, the use of the ephemeral key is stopped, and any connected session using the key is immediately disconnected.
|
||||
|
||||
During the timeout interval, the ephemeral key can be used only once by an external commissioner to establish a connection. After the commissioner disconnects, the ephemeral key is cleared, and the Border Agent reverts to using PSKc. If the timeout expires while a commissioner is still connected, the session will be terminated, and the Border Agent will cease using the ephemeral key and revert to PSKc.
|
||||
The Ephemeral Key Manager limits the number of failed DTLS connections to 10 attempts. After the 10th failed attempt, the use of the ephemeral key is automatically stopped (even if the timeout has not yet expired).
|
||||
|
||||
```bash
|
||||
> ba ephemeralkey set Z10X20g3J15w1000P60m16 5000 1234
|
||||
> ba ephemeralkey start Z10X20g3J15w1000P60m16 5000 1234
|
||||
Done
|
||||
|
||||
> ba ephemeralkey
|
||||
Started
|
||||
Done
|
||||
|
||||
> ba ephemeralkey port
|
||||
1234
|
||||
Done
|
||||
```
|
||||
|
||||
### ba ephemeralkey clear
|
||||
### ba ephemeralkey stop
|
||||
|
||||
Cancels the ephemeral key in use if any.
|
||||
Stops the ephemeral key use and disconnects any session using it.
|
||||
|
||||
Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
|
||||
Can be used to cancel a previously set ephemeral key before it is used or times out. If the Border Agent is not running or there is no ephemeral key in use, calling this function has no effect.
|
||||
|
||||
If a commissioner is connected using the ephemeral key and is currently active, calling this method does not change its state. In this case the `ba ephemeralkey` will continue to return `active` until the commissioner disconnects.
|
||||
If there is no ephemeral key in use, calling this function has no effect.
|
||||
|
||||
```bash
|
||||
> ba ephemeralkey clear
|
||||
> ba ephemeralkey stop
|
||||
Done
|
||||
```
|
||||
|
||||
### ba ephemeralkey port
|
||||
|
||||
Print the port number in use by Ephemeral Key Manager.
|
||||
|
||||
Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
|
||||
```bash
|
||||
> ba ephemeralkey port
|
||||
1234
|
||||
Done
|
||||
```
|
||||
|
||||
### ba ephemeralkey callback enable
|
||||
|
||||
Enables callback from Border Agent for ephemeral key state changes.
|
||||
Enables callback from Border Agent to be notified of state changes of Border Agent's Ephemeral Key Manager.
|
||||
|
||||
Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
|
||||
```bash
|
||||
> ba ephemeralkey callback enable
|
||||
Done
|
||||
|
||||
> ba ephemeralkey set W10X12 5000 49155
|
||||
> ba ephemeralkey start W10X120 5000 49155
|
||||
Done
|
||||
|
||||
BorderAgent callback: Ephemeral key active, port:49155
|
||||
BorderAgent callback: Ephemeral key inactive
|
||||
BorderAgentEphemeralKey callback - state:Started
|
||||
BorderAgentEphemeralKey callback - state:Connected
|
||||
BorderAgentEphemeralKey callback - state:Stopped
|
||||
```
|
||||
|
||||
### ba ephemeralkey callback disable
|
||||
|
||||
Disables callback from Border Agent for ephemeral key state changes.
|
||||
Disables callback from Border Agent to be notified of state changes of Border Agent's Ephemeral Key Manager.
|
||||
|
||||
Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
|
||||
|
||||
```bash
|
||||
> ba ephemeralkey callback disable
|
||||
Done
|
||||
```
|
||||
|
||||
### ba ephemeralkey feature
|
||||
|
||||
Displays if the Ephemeral Key feature is enabled. Note that this indicates whether the ephemeral key feature is ready to use, instead of whether an ephemeral key is active.
|
||||
|
||||
```bash
|
||||
> ba ephemeralkey feature
|
||||
Enabled
|
||||
Done
|
||||
```
|
||||
|
||||
### ba ephemeralkey feature enable
|
||||
|
||||
Enables the Ephemeral Key feature.
|
||||
|
||||
```bash
|
||||
> ba ephemeralkey feature enable
|
||||
Done
|
||||
```
|
||||
|
||||
### ba ephemeralkey feature disable
|
||||
|
||||
Disables the Ephemeral Key feature.
|
||||
|
||||
```bash
|
||||
> ba ephemeralkey feature disable
|
||||
Done
|
||||
```
|
||||
|
||||
### ba counters
|
||||
|
||||
Get the border agent counter values.
|
||||
|
||||
+66
-80
@@ -459,45 +459,21 @@ template <> otError Interpreter::Process<Cmd("ba")>(Arg aArgs[])
|
||||
*/
|
||||
if (aArgs[0] == "port")
|
||||
{
|
||||
OutputLine("%hu", otBorderAgentGetUdpPort(GetInstancePtr()));
|
||||
OutputLine("%u", otBorderAgentGetUdpPort(GetInstancePtr()));
|
||||
}
|
||||
/**
|
||||
* @cli ba state
|
||||
* @code
|
||||
* ba state
|
||||
* Started
|
||||
* Active
|
||||
* Done
|
||||
* @endcode
|
||||
* @par api_copy
|
||||
* #otBorderAgentGetState
|
||||
* #otBorderAgentIsActive
|
||||
*/
|
||||
else if (aArgs[0] == "state")
|
||||
{
|
||||
static const char *const kStateStrings[] = {
|
||||
"Stopped", // (0) OT_BORDER_AGENT_STATE_STOPPED
|
||||
"Started", // (1) OT_BORDER_AGENT_STATE_STARTED
|
||||
"Active", // (2) OT_BORDER_AGENT_STATE_ACTIVE
|
||||
};
|
||||
|
||||
static_assert(0 == OT_BORDER_AGENT_STATE_STOPPED, "OT_BORDER_AGENT_STATE_STOPPED value is incorrect");
|
||||
static_assert(1 == OT_BORDER_AGENT_STATE_STARTED, "OT_BORDER_AGENT_STATE_STARTED value is incorrect");
|
||||
static_assert(2 == OT_BORDER_AGENT_STATE_ACTIVE, "OT_BORDER_AGENT_STATE_ACTIVE value is incorrect");
|
||||
|
||||
OutputLine("%s", Stringify(otBorderAgentGetState(GetInstancePtr()), kStateStrings));
|
||||
}
|
||||
/**
|
||||
* @cli ba disconnect
|
||||
* @code
|
||||
* ba disconnect
|
||||
* Done
|
||||
* @endcode
|
||||
* @par
|
||||
* Disconnects the Border Agent from any active secure sessions
|
||||
* @sa otBorderAgentDisconnect
|
||||
*/
|
||||
else if (aArgs[0] == "disconnect")
|
||||
{
|
||||
otBorderAgentDisconnect(GetInstancePtr());
|
||||
OutputLine("%s", otBorderAgentIsActive(GetInstancePtr()) ? "Active" : "Inactive");
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
|
||||
/**
|
||||
@@ -540,30 +516,53 @@ template <> otError Interpreter::Process<Cmd("ba")>(Arg aArgs[])
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
else if (aArgs[0] == "ephemeralkey")
|
||||
{
|
||||
bool enable;
|
||||
|
||||
/**
|
||||
* @cli ba ephemeralkey
|
||||
* @code
|
||||
* ba ephemeralkey
|
||||
* active
|
||||
* Stopped
|
||||
* Done
|
||||
* @endcode
|
||||
* @par api_copy
|
||||
* #otBorderAgentIsEphemeralKeyActive
|
||||
* #otBorderAgentEphemeralKeyGetState
|
||||
*/
|
||||
if (aArgs[1].IsEmpty())
|
||||
{
|
||||
OutputLine("%sactive", otBorderAgentIsEphemeralKeyActive(GetInstancePtr()) ? "" : "in");
|
||||
otBorderAgentEphemeralKeyState state = otBorderAgentEphemeralKeyGetState(GetInstancePtr());
|
||||
|
||||
OutputLine("%s", otBorderAgentEphemeralKeyStateToString(state));
|
||||
}
|
||||
/**
|
||||
* @cli ba ephemeralkey set <keystring> [timeout-in-msec] [port]
|
||||
* @cli ba ephemeralkey (enable, disable)
|
||||
* @code
|
||||
* ba ephemeralkey set Z10X20g3J15w1000P60m16 5000 1234
|
||||
* ba ephemeralkey enable
|
||||
* Done
|
||||
* @endcode
|
||||
* @code
|
||||
* ba ephemeralkey
|
||||
* Enabled
|
||||
* Done
|
||||
* @endcode
|
||||
* @cparam ba ephemeralkey @ca{enable|disable}
|
||||
* @par api_copy
|
||||
* #otBorderAgentSetEphemeralKey
|
||||
* #otBorderAgentEphemeralKeySetEnabled
|
||||
*/
|
||||
else if (aArgs[1] == "set")
|
||||
else if (ProcessEnableDisable(aArgs + 1, otBorderAgentEphemeralKeySetEnabled) == OT_ERROR_NONE)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @cli ba ephemeralkey start <keystring> [timeout-in-msec] [port]
|
||||
* @code
|
||||
* ba ephemeralkey start Z10X20g3J15w1000P60m16 5000 1234
|
||||
* Done
|
||||
* @endcode
|
||||
* @cparam ba ephemeralkey start @ca{keystring} [@ca{timeout-in-msec}] [@ca{port}]
|
||||
* @par api_copy
|
||||
* #otBorderAgentEphemeralKeyStart
|
||||
*/
|
||||
else if (aArgs[1] == "start")
|
||||
{
|
||||
uint32_t timeout = 0;
|
||||
uint16_t port = 0;
|
||||
@@ -580,70 +579,64 @@ template <> otError Interpreter::Process<Cmd("ba")>(Arg aArgs[])
|
||||
SuccessOrExit(error = aArgs[4].ParseAsUint16(port));
|
||||
}
|
||||
|
||||
error = otBorderAgentSetEphemeralKey(GetInstancePtr(), aArgs[2].GetCString(), timeout, port);
|
||||
error = otBorderAgentEphemeralKeyStart(GetInstancePtr(), aArgs[2].GetCString(), timeout, port);
|
||||
}
|
||||
/**
|
||||
* @cli ba ephemeralkey clear
|
||||
* @cli ba ephemeralkey stop
|
||||
* @code
|
||||
* ba ephemeralkey clear
|
||||
* ba ephemeralkey stop
|
||||
* Done
|
||||
* @endcode
|
||||
* @par api_copy
|
||||
* #otBorderAgentClearEphemeralKey
|
||||
* #otBorderAgentEphemeralKeyStop
|
||||
*/
|
||||
else if (aArgs[1] == "clear")
|
||||
else if (aArgs[1] == "stop")
|
||||
{
|
||||
otBorderAgentClearEphemeralKey(GetInstancePtr());
|
||||
otBorderAgentEphemeralKeyStop(GetInstancePtr());
|
||||
}
|
||||
/**
|
||||
* @cli ba ephemeralkey port
|
||||
* @code
|
||||
* ba ephemeralkey port
|
||||
* 49153
|
||||
* Done
|
||||
* @endcode
|
||||
* @par api_copy
|
||||
* #otBorderAgentEphemeralKeyGetUdpPort
|
||||
*/
|
||||
else if (aArgs[1] == "port")
|
||||
{
|
||||
OutputLine("%u", otBorderAgentEphemeralKeyGetUdpPort(GetInstancePtr()));
|
||||
}
|
||||
/**
|
||||
* @cli ba ephemeralkey callback (enable, disable)
|
||||
* @code
|
||||
* ba ephemeralkey callback enable
|
||||
* Done
|
||||
* ba ephemeralkey set W10X1 5000 49155
|
||||
* Done
|
||||
* BorderAgent callback: Ephemeral key active, port:49155
|
||||
* BorderAgent callback: Ephemeral key inactive
|
||||
* @endcode
|
||||
* @code
|
||||
* ba ephemeralkey start W10X10 5000 49155
|
||||
* Done
|
||||
* BorderAgentEphemeralKey callback - state:Started
|
||||
* BorderAgentEphemeralKey callback - state:Connected
|
||||
* @endcode
|
||||
* @cparam ba ephemeralkey callback @ca{enable|disable}
|
||||
* @par api_copy
|
||||
* #otBorderAgentSetEphemeralKeyCallback
|
||||
* #otBorderAgentEphemeralKeySetCallback
|
||||
*/
|
||||
else if (aArgs[1] == "callback")
|
||||
{
|
||||
bool enable;
|
||||
|
||||
SuccessOrExit(error = ParseEnableOrDisable(aArgs[2], enable));
|
||||
|
||||
if (enable)
|
||||
{
|
||||
otBorderAgentSetEphemeralKeyCallback(GetInstancePtr(), HandleBorderAgentEphemeralKeyStateChange, this);
|
||||
otBorderAgentEphemeralKeySetCallback(GetInstancePtr(), HandleBorderAgentEphemeralKeyStateChange, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
otBorderAgentSetEphemeralKeyCallback(GetInstancePtr(), nullptr, nullptr);
|
||||
otBorderAgentEphemeralKeySetCallback(GetInstancePtr(), nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @cli ba ephemeralkey feature (enable, disable)
|
||||
* @code
|
||||
* ba ephemeralkey feature
|
||||
* Enabled
|
||||
* Done
|
||||
* @endcode
|
||||
* @code
|
||||
* ba ephemeralkey feature enable
|
||||
* Done
|
||||
* @endcode
|
||||
* @cparam ba ephemeralkey feature [@ca{enable|disable}]
|
||||
* @par api_copy
|
||||
* #otBorderAgentIsEphemeralKeyFeatureEnabled
|
||||
* #otBorderAgentSetEphemeralKeyFeatureEnabled
|
||||
*/
|
||||
else if (aArgs[1] == "feature")
|
||||
{
|
||||
error = ProcessEnableDisable(aArgs + 2, otBorderAgentIsEphemeralKeyFeatureEnabled,
|
||||
otBorderAgentSetEphemeralKeyFeatureEnabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = OT_ERROR_INVALID_ARGS;
|
||||
@@ -732,16 +725,9 @@ void Interpreter::HandleBorderAgentEphemeralKeyStateChange(void *aContext)
|
||||
|
||||
void Interpreter::HandleBorderAgentEphemeralKeyStateChange(void)
|
||||
{
|
||||
bool active = otBorderAgentIsEphemeralKeyActive(GetInstancePtr());
|
||||
otBorderAgentEphemeralKeyState state = otBorderAgentEphemeralKeyGetState(GetInstancePtr());
|
||||
|
||||
OutputFormat("BorderAgent callback: Ephemeral key %sactive", active ? "" : "in");
|
||||
|
||||
if (active)
|
||||
{
|
||||
OutputFormat(", port:%u", otBorderAgentGetUdpPort(GetInstancePtr()));
|
||||
}
|
||||
|
||||
OutputNewLine();
|
||||
OutputLine("BorderAgentEphemeralKey callback - state:%s", otBorderAgentEphemeralKeyStateToString(state));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -54,24 +54,9 @@ otError otBorderAgentSetId(otInstance *aInstance, const otBorderAgentId *aId)
|
||||
}
|
||||
#endif
|
||||
|
||||
otBorderAgentState otBorderAgentGetState(otInstance *aInstance)
|
||||
bool otBorderAgentIsActive(otInstance *aInstance)
|
||||
{
|
||||
otBorderAgentState state = OT_BORDER_AGENT_STATE_STOPPED;
|
||||
|
||||
switch (AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().GetState())
|
||||
{
|
||||
case MeshCoP::BorderAgent::kStateStopped:
|
||||
break;
|
||||
case MeshCoP::BorderAgent::kStateStarted:
|
||||
state = OT_BORDER_AGENT_STATE_STARTED;
|
||||
break;
|
||||
case MeshCoP::BorderAgent::kStateConnected:
|
||||
case MeshCoP::BorderAgent::kStateAccepted:
|
||||
state = OT_BORDER_AGENT_STATE_ACTIVE;
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
return AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().IsActive();
|
||||
}
|
||||
|
||||
uint16_t otBorderAgentGetUdpPort(otInstance *aInstance)
|
||||
@@ -79,52 +64,57 @@ uint16_t otBorderAgentGetUdpPort(otInstance *aInstance)
|
||||
return AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().GetUdpPort();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
|
||||
bool otBorderAgentIsEphemeralKeyFeatureEnabled(otInstance *aInstance)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().IsEphemeralKeyFeatureEnabled();
|
||||
}
|
||||
|
||||
void otBorderAgentSetEphemeralKeyFeatureEnabled(otInstance *aInstance, bool aEnabled)
|
||||
{
|
||||
AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().SetEphemeralKeyFeatureEnabled(aEnabled);
|
||||
}
|
||||
|
||||
otError otBorderAgentSetEphemeralKey(otInstance *aInstance,
|
||||
const char *aKeyString,
|
||||
uint32_t aTimeout,
|
||||
uint16_t aUdpPort)
|
||||
{
|
||||
AssertPointerIsNotNull(aKeyString);
|
||||
|
||||
return AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().SetEphemeralKey(aKeyString, aTimeout, aUdpPort);
|
||||
}
|
||||
|
||||
void otBorderAgentClearEphemeralKey(otInstance *aInstance)
|
||||
{
|
||||
AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().ClearEphemeralKey();
|
||||
}
|
||||
|
||||
bool otBorderAgentIsEphemeralKeyActive(otInstance *aInstance)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive();
|
||||
}
|
||||
|
||||
void otBorderAgentSetEphemeralKeyCallback(otInstance *aInstance,
|
||||
otBorderAgentEphemeralKeyCallback aCallback,
|
||||
void *aContext)
|
||||
{
|
||||
AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().SetEphemeralKeyCallback(aCallback, aContext);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
|
||||
const otBorderAgentCounters *otBorderAgentGetCounters(otInstance *aInstance)
|
||||
{
|
||||
return &AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().GetCounters();
|
||||
}
|
||||
|
||||
void otBorderAgentDisconnect(otInstance *aInstance) { AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().Disconnect(); }
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
|
||||
otBorderAgentEphemeralKeyState otBorderAgentEphemeralKeyGetState(otInstance *aInstance)
|
||||
{
|
||||
return MapEnum(AsCoreType(aInstance).Get<MeshCoP::BorderAgent::EphemeralKeyManager>().GetState());
|
||||
}
|
||||
|
||||
void otBorderAgentEphemeralKeySetEnabled(otInstance *aInstance, bool aEnabled)
|
||||
{
|
||||
AsCoreType(aInstance).Get<MeshCoP::BorderAgent::EphemeralKeyManager>().SetEnabled(aEnabled);
|
||||
}
|
||||
|
||||
otError otBorderAgentEphemeralKeyStart(otInstance *aInstance,
|
||||
const char *aKeyString,
|
||||
uint32_t aTimeout,
|
||||
uint16_t aUdpPort)
|
||||
{
|
||||
AssertPointerIsNotNull(aKeyString);
|
||||
|
||||
return AsCoreType(aInstance).Get<MeshCoP::BorderAgent::EphemeralKeyManager>().Start(aKeyString, aTimeout, aUdpPort);
|
||||
}
|
||||
|
||||
void otBorderAgentEphemeralKeyStop(otInstance *aInstance)
|
||||
{
|
||||
AsCoreType(aInstance).Get<MeshCoP::BorderAgent::EphemeralKeyManager>().Stop();
|
||||
}
|
||||
|
||||
uint16_t otBorderAgentEphemeralKeyGetUdpPort(otInstance *aInstance)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<MeshCoP::BorderAgent::EphemeralKeyManager>().GetUdpPort();
|
||||
}
|
||||
|
||||
void otBorderAgentEphemeralKeySetCallback(otInstance *aInstance,
|
||||
otBorderAgentEphemeralKeyCallback aCallback,
|
||||
void *aContext)
|
||||
{
|
||||
AsCoreType(aInstance).Get<MeshCoP::BorderAgent::EphemeralKeyManager>().SetCallback(aCallback, aContext);
|
||||
}
|
||||
|
||||
const char *otBorderAgentEphemeralKeyStateToString(otBorderAgentEphemeralKeyState aState)
|
||||
{
|
||||
OT_ASSERT(aState <= OT_BORDER_AGENT_STATE_ACCEPTED);
|
||||
|
||||
return MeshCoP::BorderAgent::EphemeralKeyManager::StateToString(MapEnum(aState));
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_FEATURE_ENABLED_BY_DEFAULT
|
||||
#define OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_FEATURE_ENABLED_BY_DEFAULT \
|
||||
(OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_4)
|
||||
OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
||||
@@ -1024,6 +1024,13 @@ template <> inline MeshCoP::DatasetUpdater &Instance::Get(void) { return mDatase
|
||||
template <> inline MeshCoP::BorderAgent &Instance::Get(void) { return mBorderAgent; }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
template <> inline MeshCoP::BorderAgent::EphemeralKeyManager &Instance::Get(void)
|
||||
{
|
||||
return mBorderAgent.GetEphemeralKeyManager();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_ANNOUNCE_SENDER_ENABLE
|
||||
template <> inline AnnounceSender &Instance::Get(void) { return mAnnounceSender; }
|
||||
#endif
|
||||
|
||||
+266
-181
@@ -54,12 +54,7 @@ BorderAgent::BorderAgent(Instance &aInstance)
|
||||
, mIdInitialized(false)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
, mIsEphemeralKeyFeatureEnabled(OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_FEATURE_ENABLED_BY_DEFAULT)
|
||||
, mUsingEphemeralKey(false)
|
||||
, mDidConnectWithEphemeralKey(false)
|
||||
, mOldUdpPort(0)
|
||||
, mEphemeralKeyTimer(aInstance)
|
||||
, mEphemeralKeyTask(aInstance)
|
||||
, mEphemeralKeyManager(aInstance)
|
||||
#endif
|
||||
{
|
||||
ClearAllBytes(mCounters);
|
||||
@@ -120,16 +115,8 @@ Error BorderAgent::Start(uint16_t aUdpPort, const uint8_t *aPsk, uint8_t aPskLen
|
||||
|
||||
VerifyOrExit(mState == kStateStopped);
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
if (mUsingEphemeralKey)
|
||||
{
|
||||
SuccessOrExit(error = mDtlsTransport.SetMaxConnectionAttempts(kMaxEphemeralKeyConnectionAttempts,
|
||||
HandleDtlsTransportClosed, this));
|
||||
}
|
||||
#endif
|
||||
|
||||
mDtlsTransport.SetAcceptCallback(HandleAcceptSession, this);
|
||||
mDtlsTransport.SetRemoveSessionCallback(HandleRemoveSession, this);
|
||||
mDtlsTransport.SetAcceptCallback(BorderAgent::HandleAcceptSession, this);
|
||||
mDtlsTransport.SetRemoveSessionCallback(BorderAgent::HandleRemoveSession, this);
|
||||
|
||||
SuccessOrExit(error = mDtlsTransport.Open());
|
||||
SuccessOrExit(error = mDtlsTransport.Bind(aUdpPort));
|
||||
@@ -149,15 +136,6 @@ void BorderAgent::Stop(void)
|
||||
{
|
||||
VerifyOrExit(mState != kStateStopped);
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
if (mUsingEphemeralKey)
|
||||
{
|
||||
mUsingEphemeralKey = false;
|
||||
mEphemeralKeyTimer.Stop();
|
||||
mEphemeralKeyTask.Post();
|
||||
}
|
||||
#endif
|
||||
|
||||
mDtlsTransport.Close();
|
||||
|
||||
mState = kStateStopped;
|
||||
@@ -167,17 +145,6 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void BorderAgent::Disconnect(void)
|
||||
{
|
||||
VerifyOrExit(mState == kStateConnected || mState == kStateAccepted);
|
||||
VerifyOrExit(mCoapDtlsSession != nullptr);
|
||||
|
||||
mCoapDtlsSession->Disconnect();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t BorderAgent::GetUdpPort(void) const { return mDtlsTransport.GetUdpPort(); }
|
||||
|
||||
void BorderAgent::HandleNotifierEvents(Events aEvents)
|
||||
@@ -196,23 +163,16 @@ void BorderAgent::HandleNotifierEvents(Events aEvents)
|
||||
|
||||
if (aEvents.ContainsAny(kEventPskcChanged))
|
||||
{
|
||||
Pskc pskc;
|
||||
|
||||
VerifyOrExit(mState != kStateStopped);
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
// No-op if Ephemeralkey mode is activated, new pskc will be applied
|
||||
// when Ephemeralkey mode is deactivated.
|
||||
VerifyOrExit(!mUsingEphemeralKey);
|
||||
#endif
|
||||
Get<KeyManager>().GetPskc(pskc);
|
||||
|
||||
{
|
||||
Pskc pskc;
|
||||
Get<KeyManager>().GetPskc(pskc);
|
||||
|
||||
// If there is secure session already established, it won't be impacted,
|
||||
// new pskc will be applied for next connection.
|
||||
SuccessOrExit(mDtlsTransport.SetPsk(pskc.m8, Pskc::kSize));
|
||||
pskc.Clear();
|
||||
}
|
||||
// If there is secure session already established, it won't be impacted,
|
||||
// new pskc will be applied for next connection.
|
||||
SuccessOrExit(mDtlsTransport.SetPsk(pskc.m8, Pskc::kSize));
|
||||
pskc.Clear();
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -241,60 +201,45 @@ exit:
|
||||
return session;
|
||||
}
|
||||
|
||||
void BorderAgent::HandleRemoveSession(void *aContext, SecureSession &aSesssion)
|
||||
void BorderAgent::HandleRemoveSession(void *aContext, SecureSession &aSession)
|
||||
{
|
||||
static_cast<BorderAgent *>(aContext)->HandleRemoveSession(aSesssion);
|
||||
static_cast<BorderAgent *>(aContext)->HandleRemoveSession(aSession);
|
||||
}
|
||||
|
||||
void BorderAgent::HandleRemoveSession(SecureSession &aSesssion)
|
||||
void BorderAgent::HandleRemoveSession(SecureSession &aSession)
|
||||
{
|
||||
CoapDtlsSession &coapSession = static_cast<CoapDtlsSession &>(aSesssion);
|
||||
CoapDtlsSession &coapSession = static_cast<CoapDtlsSession &>(aSession);
|
||||
|
||||
coapSession.Cleanup();
|
||||
coapSession.Free();
|
||||
mCoapDtlsSession = nullptr;
|
||||
}
|
||||
|
||||
void BorderAgent::HandleSessionConnected(CoapDtlsSession &aSesssion)
|
||||
void BorderAgent::HandleSessionConnected(CoapDtlsSession &aSession)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aSesssion);
|
||||
|
||||
mState = kStateConnected;
|
||||
OT_UNUSED_VARIABLE(aSession);
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
if (mUsingEphemeralKey)
|
||||
if (mEphemeralKeyManager.OwnsSession(aSession))
|
||||
{
|
||||
mDidConnectWithEphemeralKey = true;
|
||||
mCounters.mEpskcSecureSessionSuccesses++;
|
||||
mEphemeralKeyTask.Post();
|
||||
mEphemeralKeyManager.HandleSessionConnected();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
mState = kStateConnected;
|
||||
mCounters.mPskcSecureSessionSuccesses++;
|
||||
}
|
||||
}
|
||||
|
||||
void BorderAgent::HandleSessionDisconnected(CoapDtlsSession &aSesssion, CoapDtlsSession::ConnectEvent aEvent)
|
||||
void BorderAgent::HandleSessionDisconnected(CoapDtlsSession &aSession, CoapDtlsSession::ConnectEvent aEvent)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aSesssion);
|
||||
OT_UNUSED_VARIABLE(aSession);
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
if (mUsingEphemeralKey)
|
||||
if (mEphemeralKeyManager.OwnsSession(aSession))
|
||||
{
|
||||
if (mDidConnectWithEphemeralKey)
|
||||
{
|
||||
RestartAfterRemovingEphemeralKey();
|
||||
}
|
||||
|
||||
if (aEvent == CoapDtlsSession::kDisconnectedError)
|
||||
{
|
||||
mCounters.mEpskcSecureSessionFailures++;
|
||||
}
|
||||
else if (aEvent == CoapDtlsSession::kDisconnectedPeerClosed)
|
||||
{
|
||||
mCounters.mEpskcDeactivationDisconnects++;
|
||||
}
|
||||
mEphemeralKeyManager.HandleSessionDisconnected(aEvent);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -308,20 +253,19 @@ void BorderAgent::HandleSessionDisconnected(CoapDtlsSession &aSesssion, CoapDtls
|
||||
}
|
||||
}
|
||||
|
||||
void BorderAgent::HandleCommissionerPetitionAccepted(CoapDtlsSession &aSesssion)
|
||||
void BorderAgent::HandleCommissionerPetitionAccepted(CoapDtlsSession &aSession)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aSesssion);
|
||||
|
||||
mState = kStateAccepted;
|
||||
OT_UNUSED_VARIABLE(aSession);
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
if (mUsingEphemeralKey)
|
||||
if (mEphemeralKeyManager.OwnsSession(aSession))
|
||||
{
|
||||
mCounters.mEpskcCommissionerPetitions++;
|
||||
mEphemeralKeyManager.HandleCommissionerPetitionAccepted();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
mState = kStateAccepted;
|
||||
mCounters.mPskcCommissionerPetitions++;
|
||||
}
|
||||
}
|
||||
@@ -373,95 +317,130 @@ exit:
|
||||
FreeMessageOnError(message, error);
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Ephemeral Key
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// BorderAgent::EphemeralKeyManager
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
|
||||
Error BorderAgent::SetEphemeralKey(const char *aKeyString, uint32_t aTimeout, uint16_t aUdpPort)
|
||||
BorderAgent::EphemeralKeyManager::EphemeralKeyManager(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_FEATURE_ENABLED_BY_DEFAULT
|
||||
, mState(kStateStopped)
|
||||
#else
|
||||
, mState(kStateDisabled)
|
||||
#endif
|
||||
, mDtlsTransport(aInstance, kNoLinkSecurity)
|
||||
, mCoapDtlsSession(nullptr)
|
||||
, mTimer(aInstance)
|
||||
, mCallbackTask(aInstance)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
uint16_t length = StringLength(aKeyString, kMaxEphemeralKeyLength + 1);
|
||||
}
|
||||
|
||||
VerifyOrExit(mIsEphemeralKeyFeatureEnabled, error = kErrorNotCapable);
|
||||
VerifyOrExit(mState == kStateStarted, error = kErrorInvalidState);
|
||||
VerifyOrExit((length >= kMinEphemeralKeyLength) && (length <= kMaxEphemeralKeyLength), error = kErrorInvalidArgs);
|
||||
|
||||
if (!mUsingEphemeralKey)
|
||||
void BorderAgent::EphemeralKeyManager::SetEnabled(bool aEnabled)
|
||||
{
|
||||
if (aEnabled)
|
||||
{
|
||||
mOldUdpPort = GetUdpPort();
|
||||
VerifyOrExit(mState == kStateDisabled);
|
||||
SetState(kStateStopped);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(mState != kStateDisabled);
|
||||
Stop();
|
||||
SetState(kStateDisabled);
|
||||
}
|
||||
|
||||
Stop();
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
// We set the `mUsingEphemeralKey` before `Start()` since
|
||||
// callbacks (like `HandleConnected()`) may be invoked from
|
||||
// `Start()` itself.
|
||||
Error BorderAgent::EphemeralKeyManager::Start(const char *aKeyString, uint32_t aTimeout, uint16_t aUdpPort)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
uint16_t length;
|
||||
|
||||
mUsingEphemeralKey = true;
|
||||
mDidConnectWithEphemeralKey = false;
|
||||
VerifyOrExit(mState == kStateStopped, error = kErrorInvalidState);
|
||||
|
||||
error = Start(aUdpPort, reinterpret_cast<const uint8_t *>(aKeyString), static_cast<uint8_t>(length));
|
||||
length = StringLength(aKeyString, kMaxKeyLength + 1);
|
||||
VerifyOrExit((length >= kMinKeyLength) && (length <= kMaxKeyLength), error = kErrorInvalidArgs);
|
||||
|
||||
if (error != kErrorNone)
|
||||
{
|
||||
mUsingEphemeralKey = false;
|
||||
IgnoreError(Start(mOldUdpPort));
|
||||
mCounters.mEpskcStartSecureSessionErrors++;
|
||||
ExitNow();
|
||||
}
|
||||
IgnoreError(mDtlsTransport.SetMaxConnectionAttempts(kMaxConnectionAttempts, HandleTransportClosed, this));
|
||||
|
||||
mEphemeralKeyTask.Post();
|
||||
mDtlsTransport.SetAcceptCallback(EphemeralKeyManager::HandleAcceptSession, this);
|
||||
mDtlsTransport.SetRemoveSessionCallback(EphemeralKeyManager::HandleRemoveSession, this);
|
||||
|
||||
if (aTimeout == 0)
|
||||
{
|
||||
aTimeout = kDefaultEphemeralKeyTimeout;
|
||||
}
|
||||
SuccessOrExit(error = mDtlsTransport.Open());
|
||||
SuccessOrExit(error = mDtlsTransport.Bind(aUdpPort));
|
||||
|
||||
aTimeout = Min(aTimeout, kMaxEphemeralKeyTimeout);
|
||||
SuccessOrExit(
|
||||
error = mDtlsTransport.SetPsk(reinterpret_cast<const uint8_t *>(aKeyString), static_cast<uint8_t>(length)));
|
||||
|
||||
mEphemeralKeyTimer.Start(aTimeout);
|
||||
mCounters.mEpskcActivations++;
|
||||
aTimeout = Min((aTimeout == 0) ? kDefaultTimeout : aTimeout, kMaxTimeout);
|
||||
mTimer.Start(aTimeout);
|
||||
|
||||
LogInfo("Allow ephemeral key for %lu msec on port %u", ToUlong(aTimeout), GetUdpPort());
|
||||
|
||||
SetState(kStateStarted);
|
||||
|
||||
exit:
|
||||
switch (error)
|
||||
{
|
||||
case kErrorNone:
|
||||
Get<BorderAgent>().mCounters.mEpskcActivations++;
|
||||
break;
|
||||
case kErrorInvalidState:
|
||||
mCounters.mEpskcInvalidBaStateErrors++;
|
||||
Get<BorderAgent>().mCounters.mEpskcInvalidBaStateErrors++;
|
||||
break;
|
||||
case kErrorInvalidArgs:
|
||||
mCounters.mEpskcInvalidArgsErrors++;
|
||||
Get<BorderAgent>().mCounters.mEpskcInvalidArgsErrors++;
|
||||
break;
|
||||
default:
|
||||
Get<BorderAgent>().mCounters.mEpskcStartSecureSessionErrors++;
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void BorderAgent::ClearEphemeralKey(void)
|
||||
void BorderAgent::EphemeralKeyManager::Stop(void) { Stop(kReasonLocalDisconnect); }
|
||||
|
||||
void BorderAgent::EphemeralKeyManager::Stop(StopReason aReason)
|
||||
{
|
||||
VerifyOrExit(mUsingEphemeralKey);
|
||||
|
||||
LogInfo("Clearing ephemeral key");
|
||||
|
||||
mCounters.mEpskcDeactivationClears++;
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case kStateStarted:
|
||||
RestartAfterRemovingEphemeralKey();
|
||||
break;
|
||||
|
||||
case kStateStopped:
|
||||
case kStateConnected:
|
||||
case kStateAccepted:
|
||||
// If a commissioner connection is currently active, we'll
|
||||
// wait for it to disconnect or for the ephemeral key timeout
|
||||
// or `kKeepAliveTimeout` to expire before removing the key
|
||||
// and restarting the agent.
|
||||
break;
|
||||
case kStateDisabled:
|
||||
case kStateStopped:
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
LogInfo("Stopping ephemeral key use - reason: %s", StopReasonToString(aReason));
|
||||
SetState(kStateStopped);
|
||||
|
||||
mTimer.Stop();
|
||||
mDtlsTransport.Close();
|
||||
|
||||
switch (aReason)
|
||||
{
|
||||
case kReasonLocalDisconnect:
|
||||
Get<BorderAgent>().mCounters.mEpskcDeactivationClears++;
|
||||
break;
|
||||
case kReasonPeerDisconnect:
|
||||
Get<BorderAgent>().mCounters.mEpskcDeactivationDisconnects++;
|
||||
break;
|
||||
case kReasonSessionError:
|
||||
Get<BorderAgent>().mCounters.mEpskcStartSecureSessionErrors++;
|
||||
break;
|
||||
case kReasonMaxFailedAttempts:
|
||||
Get<BorderAgent>().mCounters.mEpskcDeactivationMaxAttempts++;
|
||||
break;
|
||||
case kReasonTimeout:
|
||||
Get<BorderAgent>().mCounters.mEpskcDeactivationTimeouts++;
|
||||
break;
|
||||
case kReasonUnknown:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -469,56 +448,162 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void BorderAgent::HandleEphemeralKeyTimeout(void)
|
||||
void BorderAgent::EphemeralKeyManager::SetState(State aState)
|
||||
{
|
||||
LogInfo("Ephemeral key timed out");
|
||||
mCounters.mEpskcDeactivationTimeouts++;
|
||||
RestartAfterRemovingEphemeralKey();
|
||||
}
|
||||
|
||||
void BorderAgent::InvokeEphemeralKeyCallback(void) { mEphemeralKeyCallback.InvokeIfSet(); }
|
||||
|
||||
void BorderAgent::RestartAfterRemovingEphemeralKey(void)
|
||||
{
|
||||
LogInfo("Removing ephemeral key and restarting agent");
|
||||
|
||||
Stop();
|
||||
IgnoreError(Start(mOldUdpPort));
|
||||
}
|
||||
|
||||
void BorderAgent::HandleDtlsTransportClosed(void *aContext)
|
||||
{
|
||||
reinterpret_cast<BorderAgent *>(aContext)->HandleDtlsTransportClosed();
|
||||
}
|
||||
|
||||
void BorderAgent::HandleDtlsTransportClosed(void)
|
||||
{
|
||||
LogInfo("Reached max allowed connection attempts with ephemeral key");
|
||||
mCounters.mEpskcDeactivationMaxAttempts++;
|
||||
RestartAfterRemovingEphemeralKey();
|
||||
}
|
||||
|
||||
void BorderAgent::SetEphemeralKeyFeatureEnabled(bool aEnabled)
|
||||
{
|
||||
VerifyOrExit(mIsEphemeralKeyFeatureEnabled != aEnabled);
|
||||
mIsEphemeralKeyFeatureEnabled = aEnabled;
|
||||
|
||||
if (!mIsEphemeralKeyFeatureEnabled)
|
||||
{
|
||||
// If there is an active session connected with ephemeral key, we disconnect
|
||||
// the session.
|
||||
if (mUsingEphemeralKey)
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
ClearEphemeralKey();
|
||||
}
|
||||
|
||||
// TODO: Update MeshCoP service after new module is added.
|
||||
VerifyOrExit(mState != aState);
|
||||
LogInfo("Ephemeral key - state: %s -> %s", StateToString(mState), StateToString(aState));
|
||||
mState = aState;
|
||||
mCallbackTask.Post();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
SecureSession *BorderAgent::EphemeralKeyManager::HandleAcceptSession(void *aContext,
|
||||
const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aMessageInfo);
|
||||
|
||||
return static_cast<EphemeralKeyManager *>(aContext)->HandleAcceptSession();
|
||||
}
|
||||
|
||||
BorderAgent::CoapDtlsSession *BorderAgent::EphemeralKeyManager::HandleAcceptSession(void)
|
||||
{
|
||||
CoapDtlsSession *session = nullptr;
|
||||
|
||||
VerifyOrExit(mCoapDtlsSession == nullptr);
|
||||
|
||||
session = CoapDtlsSession::Allocate(GetInstance(), mDtlsTransport);
|
||||
VerifyOrExit(session != nullptr);
|
||||
|
||||
mCoapDtlsSession = session;
|
||||
|
||||
exit:
|
||||
return session;
|
||||
}
|
||||
|
||||
void BorderAgent::EphemeralKeyManager::HandleRemoveSession(void *aContext, SecureSession &aSession)
|
||||
{
|
||||
static_cast<EphemeralKeyManager *>(aContext)->HandleRemoveSession(aSession);
|
||||
}
|
||||
|
||||
void BorderAgent::EphemeralKeyManager::HandleRemoveSession(SecureSession &aSession)
|
||||
{
|
||||
CoapDtlsSession &coapSession = static_cast<CoapDtlsSession &>(aSession);
|
||||
|
||||
coapSession.Cleanup();
|
||||
coapSession.Free();
|
||||
mCoapDtlsSession = nullptr;
|
||||
}
|
||||
|
||||
void BorderAgent::EphemeralKeyManager::HandleSessionConnected(void)
|
||||
{
|
||||
SetState(kStateConnected);
|
||||
Get<BorderAgent>().mCounters.mEpskcSecureSessionSuccesses++;
|
||||
}
|
||||
|
||||
void BorderAgent::EphemeralKeyManager::HandleSessionDisconnected(SecureSession::ConnectEvent aEvent)
|
||||
{
|
||||
StopReason reason = kReasonUnknown;
|
||||
|
||||
// The ephemeral key can be used once
|
||||
|
||||
VerifyOrExit((mState == kStateConnected) || (mState == kStateAccepted));
|
||||
|
||||
switch (aEvent)
|
||||
{
|
||||
case SecureSession::kDisconnectedError:
|
||||
reason = kReasonSessionError;
|
||||
break;
|
||||
case SecureSession::kDisconnectedPeerClosed:
|
||||
reason = kReasonPeerDisconnect;
|
||||
break;
|
||||
case SecureSession::kDisconnectedMaxAttempts:
|
||||
reason = kReasonMaxFailedAttempts;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Stop(reason);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void BorderAgent::EphemeralKeyManager::HandleCommissionerPetitionAccepted(void)
|
||||
{
|
||||
SetState(kStateAccepted);
|
||||
Get<BorderAgent>().mCounters.mEpskcCommissionerPetitions++;
|
||||
}
|
||||
|
||||
void BorderAgent::EphemeralKeyManager::HandleTimer(void) { Stop(kReasonTimeout); }
|
||||
|
||||
void BorderAgent::EphemeralKeyManager::HandleTask(void) { mCallback.InvokeIfSet(); }
|
||||
|
||||
void BorderAgent::EphemeralKeyManager::HandleTransportClosed(void *aContext)
|
||||
{
|
||||
reinterpret_cast<EphemeralKeyManager *>(aContext)->HandleTransportClosed();
|
||||
}
|
||||
|
||||
void BorderAgent::EphemeralKeyManager::HandleTransportClosed(void)
|
||||
{
|
||||
Stop(kReasonMaxFailedAttempts);
|
||||
;
|
||||
}
|
||||
|
||||
const char *BorderAgent::EphemeralKeyManager::StateToString(State aState)
|
||||
{
|
||||
static const char *const kStateStrings[] = {
|
||||
"Disabled", // (0) kStateDisabled
|
||||
"Stopped", // (1) kStateStopped
|
||||
"Started", // (2) kStateStarted
|
||||
"Connected", // (3) kStateConnected
|
||||
"Accepted", // (4) kStateAccepted
|
||||
};
|
||||
|
||||
struct EnumCheck
|
||||
{
|
||||
InitEnumValidatorCounter();
|
||||
ValidateNextEnum(kStateDisabled);
|
||||
ValidateNextEnum(kStateStopped);
|
||||
ValidateNextEnum(kStateStarted);
|
||||
ValidateNextEnum(kStateConnected);
|
||||
ValidateNextEnum(kStateAccepted);
|
||||
};
|
||||
|
||||
return kStateStrings[aState];
|
||||
}
|
||||
|
||||
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
||||
|
||||
const char *BorderAgent::EphemeralKeyManager::StopReasonToString(StopReason aReason)
|
||||
{
|
||||
static const char *const kReasonStrings[] = {
|
||||
"LocalDisconnect", // (0) kReasonLocalDisconnect
|
||||
"PeerDisconnect", // (1) kReasonPeerDisconnect
|
||||
"SessionError", // (2) kReasonSessionError
|
||||
"MaxFailedAttempts", // (3) kReasonMaxFailedAttempts
|
||||
"Timeout", // (4) kReasonTimeout
|
||||
"Unknown", // (5) kReasonUnknown
|
||||
};
|
||||
|
||||
struct EnumCheck
|
||||
{
|
||||
InitEnumValidatorCounter();
|
||||
ValidateNextEnum(kReasonLocalDisconnect);
|
||||
ValidateNextEnum(kReasonPeerDisconnect);
|
||||
ValidateNextEnum(kReasonSessionError);
|
||||
ValidateNextEnum(kReasonMaxFailedAttempts);
|
||||
ValidateNextEnum(kReasonTimeout);
|
||||
ValidateNextEnum(kReasonUnknown);
|
||||
};
|
||||
|
||||
return kReasonStrings[aReason];
|
||||
}
|
||||
|
||||
#endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
@@ -987,11 +1072,11 @@ void BorderAgent::CoapDtlsSession::HandleTimer(void)
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// `BorderAgent::CoapDtlsSession::ForwardContext`
|
||||
|
||||
BorderAgent::CoapDtlsSession::ForwardContext::ForwardContext(CoapDtlsSession &aSesssion,
|
||||
BorderAgent::CoapDtlsSession::ForwardContext::ForwardContext(CoapDtlsSession &aSession,
|
||||
const Coap::Message &aMessage,
|
||||
bool aPetition,
|
||||
bool aSeparate)
|
||||
: mSession(aSesssion)
|
||||
: mSession(aSession)
|
||||
, mMessageId(aMessage.GetMessageId())
|
||||
, mPetition(aPetition)
|
||||
, mSeparate(aSeparate)
|
||||
|
||||
+159
-138
@@ -66,39 +66,19 @@ class BorderAgent : public InstanceLocator, private NonCopyable
|
||||
friend class ot::Notifier;
|
||||
friend class Tmf::Agent;
|
||||
|
||||
class CoapDtlsSession;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Minimum length of the ephemeral key string.
|
||||
*/
|
||||
static constexpr uint16_t kMinEphemeralKeyLength = OT_BORDER_AGENT_MIN_EPHEMERAL_KEY_LENGTH;
|
||||
|
||||
/**
|
||||
* Maximum length of the ephemeral key string.
|
||||
*/
|
||||
static constexpr uint16_t kMaxEphemeralKeyLength = OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_LENGTH;
|
||||
|
||||
/**
|
||||
* Default ephemeral key timeout interval in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kDefaultEphemeralKeyTimeout = OT_BORDER_AGENT_DEFAULT_EPHEMERAL_KEY_TIMEOUT;
|
||||
|
||||
/**
|
||||
* Maximum ephemeral key timeout interval in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kMaxEphemeralKeyTimeout = OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT;
|
||||
|
||||
typedef otBorderAgentId Id; ///< Border Agent ID.
|
||||
typedef otBorderAgentCounters Counters; ///< Border Agent Counters.
|
||||
|
||||
/**
|
||||
* Defines the Border Agent state.
|
||||
*/
|
||||
enum State : uint8_t
|
||||
{
|
||||
kStateStopped, ///< Stopped/disabled.
|
||||
kStateStarted, ///< Started and listening for connections.
|
||||
kStateConnected, ///< Connected to an external commissioner candidate, petition pending.
|
||||
kStateAccepted, ///< Connected to and accepted an external commissioner.
|
||||
kStateDisabled = OT_BORDER_AGENT_STATE_DISABLED, ///< Ephemeral key feature is disabled.
|
||||
kStateStopped = OT_BORDER_AGENT_STATE_STOPPED, ///< Enabled, but the ephemeral key is not set and started.
|
||||
kStateStarted = OT_BORDER_AGENT_STATE_STARTED, ///< Ephemeral key is set and listening to accept connection
|
||||
kStateConnected = OT_BORDER_AGENT_STATE_CONNECTED, ///< Session connected with candidate, not full commissioner
|
||||
kStateAccepted = OT_BORDER_AGENT_STATE_ACCEPTED, ///< Session connected and accepted as full commissioner.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -153,95 +133,161 @@ public:
|
||||
State GetState(void) const { return mState; }
|
||||
|
||||
/**
|
||||
* Disconnects the Border Agent from any active secure sessions.
|
||||
* Indicates whether the Border Agent service is active.
|
||||
*
|
||||
* If Border Agent is connected to a commissioner candidate with ephemeral key, calling this API
|
||||
* will cause the ephemeral key to be cleared after the session is disconnected.
|
||||
*
|
||||
* The Border Agent state may not change immediately upon calling this method, the state will be
|
||||
* updated when the connection update is notified by `HandleConnected()`.
|
||||
* @retval TRUE Border Agent service is active.
|
||||
* @retval FALSE Border Agent service is not active.
|
||||
*/
|
||||
void Disconnect(void);
|
||||
bool IsActive(void) const { return (mState != kStateDisabled) && (mState != kStateStopped); }
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
/**
|
||||
* Sets the ephemeral key for a given timeout duration.
|
||||
*
|
||||
* The ephemeral key can be set when the Border Agent is already running and is not currently connected to any
|
||||
* external commissioner (i.e., it is in `kStateStarted` state). To terminate active commissioner sessions,
|
||||
* use the `Disconnect()` function.
|
||||
*
|
||||
* The given @p aKeyString is directly used as the ephemeral PSK (excluding the trailing null `\0` character). Its
|
||||
* length must be between `kMinEphemeralKeyLength` and `kMaxEphemeralKeyLength`, inclusive.
|
||||
*
|
||||
* Setting the ephemeral key again before a previously set one is timed out will replace the previous one and will
|
||||
* reset the timeout.
|
||||
*
|
||||
* During the timeout interval, the ephemeral key can be used only once by an external commissioner to establish a
|
||||
* connection. After the commissioner disconnects, the ephemeral key is cleared, and the Border Agent reverts to
|
||||
* using PSKc. If the timeout expires while a commissioner is still connected, the session will be terminated, and
|
||||
* the Border Agent will cease using the ephemeral key and revert to PSKc.
|
||||
*
|
||||
* @param[in] aKeyString The ephemeral key.
|
||||
* @param[in] aTimeout The timeout duration in milliseconds to use the ephemeral key.
|
||||
* If zero, the default `kDefaultEphemeralKeyTimeout` value will be used.
|
||||
* If the timeout value is larger than `kMaxEphemeralKeyTimeout`, the max value will be
|
||||
* used instead.
|
||||
* @param[in] aUdpPort The UDP port to use with ephemeral key. If UDP port is zero, an ephemeral port will be
|
||||
* used. `GetUdpPort()` will return the current UDP port being used.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the ephemeral key.
|
||||
* @retval kErrorInvalidState Agent is not running or connected to external commissioner.
|
||||
* @retval kErrorInvalidArgs The given @p aKeyString is not valid.
|
||||
* @retval kErrorFailed Failed to set the key (e.g., could not bind to UDP port).
|
||||
* Manages the ephemeral key use by Border Agent.
|
||||
*/
|
||||
Error SetEphemeralKey(const char *aKeyString, uint32_t aTimeout, uint16_t aUdpPort);
|
||||
|
||||
/**
|
||||
* Cancels the ephemeral key in use if any.
|
||||
*
|
||||
* Can be used to cancel a previously set ephemeral key before it times out. If the Border Agent is not running or
|
||||
* there is no ephemeral key in use, calling this function has no effect.
|
||||
*
|
||||
* If a commissioner is connected using the ephemeral key and is currently active, calling this method does not
|
||||
* change its state. In this case the `IsEphemeralKeyActive()` will continue to return `true` until the commissioner
|
||||
* disconnects, or the ephemeral key timeout expires. To terminate active commissioner sessions, use the
|
||||
* `Disconnect()` function.
|
||||
*/
|
||||
void ClearEphemeralKey(void);
|
||||
|
||||
/**
|
||||
* Indicates whether or not an ephemeral key is currently active.
|
||||
*
|
||||
* @retval TRUE An ephemeral key is active.
|
||||
* @retval FALSE No ephemeral key is active.
|
||||
*/
|
||||
bool IsEphemeralKeyActive(void) const { return mUsingEphemeralKey; }
|
||||
|
||||
/**
|
||||
* Callback function pointer to notify when there is any changes related to use of ephemeral key by Border Agent.
|
||||
*/
|
||||
typedef otBorderAgentEphemeralKeyCallback EphemeralKeyCallback;
|
||||
|
||||
void SetEphemeralKeyCallback(EphemeralKeyCallback aCallback, void *aContext)
|
||||
class EphemeralKeyManager : public InstanceLocator, private NonCopyable
|
||||
{
|
||||
mEphemeralKeyCallback.Set(aCallback, aContext);
|
||||
}
|
||||
friend class BorderAgent;
|
||||
|
||||
public:
|
||||
static constexpr uint16_t kMinKeyLength = OT_BORDER_AGENT_MIN_EPHEMERAL_KEY_LENGTH; ///< Min key len.
|
||||
static constexpr uint16_t kMaxKeyLength = OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_LENGTH; ///< Max key len.
|
||||
static constexpr uint32_t kDefaultTimeout = OT_BORDER_AGENT_DEFAULT_EPHEMERAL_KEY_TIMEOUT; //< Default timeout.
|
||||
static constexpr uint32_t kMaxTimeout = OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT; ///< Max timeout.
|
||||
|
||||
typedef otBorderAgentEphemeralKeyCallback CallbackHandler; ///< Callback function pointer.
|
||||
|
||||
/**
|
||||
* Enables/disables Ephemeral Key Manager.
|
||||
*
|
||||
* If this method is called to disable, while an an ephemeral key is in use, the ephemeral key use will
|
||||
* be stopped (as if `Stop()` is called).
|
||||
*
|
||||
* @param[in] aEnabled Whether to enable or disable.
|
||||
*/
|
||||
void SetEnabled(bool aEnabled);
|
||||
|
||||
/**
|
||||
* Starts using an ephemeral key for a given timeout duration.
|
||||
*
|
||||
* An ephemeral key can only be set when `GetState()` is `kStateStopped`. Otherwise, `kErrorInvalidState` is
|
||||
* returned. This means that setting the ephemeral key again while a previously set key is still in use will
|
||||
* fail. Callers can stop the previous key by calling `Stop()` before starting with a new key.
|
||||
*
|
||||
* The given @p aKeyString is used directly as the ephemeral PSK (excluding the trailing null `\0` character).
|
||||
* Its length must be between `kMinKeyLength` and `kMaxKeyLength`, inclusive.
|
||||
*
|
||||
* The ephemeral key can be used only once by an external commissioner candidate to establish a secure session.
|
||||
* After the commissioner candidate disconnects, the use of the ephemeral key is stopped. If the timeout
|
||||
* expires, the use of the ephemeral key is also stopped, and any established session using the key is
|
||||
* immediately disconnected.
|
||||
*
|
||||
* @param[in] aKeyString The ephemeral key.
|
||||
* @param[in] aTimeout The timeout duration, in milliseconds, to use the ephemeral key.
|
||||
* If zero, the default `kDefaultTimeout` value is used. If the timeout value is
|
||||
* larger than `kMaxTimeout`, the maximum value is used instead.
|
||||
* @param[in] aUdpPort The UDP port to use with the ephemeral key. If the UDP port is zero, an ephemeral
|
||||
* port is used. `GetUdpPort()` returns the current UDP port being used.
|
||||
*
|
||||
* @retval kErrorNone Successfully started using the ephemeral key.
|
||||
* @retval kErrorInvalidState A previously set ephemeral key is still in use or feature is disabled.
|
||||
* @retval kErrorInvalidArgs The given @p aKeyString is not valid.
|
||||
* @retval kErrorFailed Failed to start (e.g., it could not bind to the given UDP port).
|
||||
*/
|
||||
Error Start(const char *aKeyString, uint32_t aTimeout, uint16_t aUdpPort);
|
||||
|
||||
/**
|
||||
* Stops the ephemeral key use and disconnects any established secure session using it.
|
||||
*
|
||||
* If there is no ephemeral key in use, calling this method has no effect.
|
||||
*/
|
||||
void Stop(void);
|
||||
|
||||
/**
|
||||
* Gets the state of ephemeral key use and its session.
|
||||
*
|
||||
* @returns The `EmpheralKeyManager` state.
|
||||
*/
|
||||
State GetState(void) const { return mState; }
|
||||
|
||||
/**
|
||||
* Gets the UDP port used by ephemeral key DTLS secure transport.
|
||||
*
|
||||
* @returns UDP port number.
|
||||
*/
|
||||
uint16_t GetUdpPort(void) const { return mDtlsTransport.GetUdpPort(); }
|
||||
|
||||
/**
|
||||
* Sets the callback.
|
||||
*
|
||||
* @param[in] aCallback The callback function pointer.
|
||||
* @param[in] aContext The context associated and used with callback handler.
|
||||
*/
|
||||
void SetCallback(CallbackHandler aCallback, void *aContext) { mCallback.Set(aCallback, aContext); }
|
||||
|
||||
/**
|
||||
* Converts a given `State` to human-readable string.
|
||||
*
|
||||
* @param[in] aState The state to convert.
|
||||
*
|
||||
* @returns The string corresponding to @p aState.
|
||||
*/
|
||||
static const char *StateToString(State aState);
|
||||
|
||||
private:
|
||||
static constexpr uint16_t kMaxConnectionAttempts = 10;
|
||||
|
||||
static_assert(kMaxKeyLength <= Dtls::Transport::kPskMaxLength, "Max e-key len is larger than max PSK len");
|
||||
|
||||
enum StopReason : uint8_t
|
||||
{
|
||||
kReasonLocalDisconnect,
|
||||
kReasonPeerDisconnect,
|
||||
kReasonSessionError,
|
||||
kReasonMaxFailedAttempts,
|
||||
kReasonTimeout,
|
||||
kReasonUnknown,
|
||||
};
|
||||
|
||||
explicit EphemeralKeyManager(Instance &aInstance);
|
||||
|
||||
void SetState(State aState);
|
||||
void Stop(StopReason aReason);
|
||||
void HandleTimer(void);
|
||||
void HandleTask(void);
|
||||
bool OwnsSession(CoapDtlsSession &aSession) const { return mCoapDtlsSession == &aSession; }
|
||||
void HandleSessionConnected(void);
|
||||
void HandleSessionDisconnected(SecureSession::ConnectEvent aEvent);
|
||||
void HandleCommissionerPetitionAccepted(void);
|
||||
|
||||
// Session or Transport callbacks
|
||||
static SecureSession *HandleAcceptSession(void *aContext, const Ip6::MessageInfo &aMessageInfo);
|
||||
CoapDtlsSession *HandleAcceptSession(void);
|
||||
static void HandleRemoveSession(void *aContext, SecureSession &aSession);
|
||||
void HandleRemoveSession(SecureSession &aSession);
|
||||
static void HandleTransportClosed(void *aContext);
|
||||
void HandleTransportClosed(void);
|
||||
|
||||
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
||||
static const char *StopReasonToString(StopReason aReason);
|
||||
#endif
|
||||
|
||||
using TimeoutTimer = TimerMilliIn<EphemeralKeyManager, &EphemeralKeyManager::HandleTimer>;
|
||||
using CallbackTask = TaskletIn<EphemeralKeyManager, &EphemeralKeyManager::HandleTask>;
|
||||
|
||||
State mState;
|
||||
Dtls::Transport mDtlsTransport;
|
||||
CoapDtlsSession *mCoapDtlsSession;
|
||||
TimeoutTimer mTimer;
|
||||
CallbackTask mCallbackTask;
|
||||
Callback<CallbackHandler> mCallback;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enables/disables the Border Agent Ephemeral Key feature.
|
||||
* Gets the `EphemeralKeyManager` instance.
|
||||
*
|
||||
* The Ephemeral Key feature can only be used when it's enabled. If an ephemeral key is already active and then
|
||||
* this method is called to disable the feature, the in-use ephemeral key will be cleared.
|
||||
*
|
||||
* @param[in] aIsEnabled Whether to enable the BA Ephemeral Key feature.
|
||||
* @returns A reference to the `EphemeralKeyManager`.
|
||||
*/
|
||||
void SetEphemeralKeyFeatureEnabled(bool aEnabled);
|
||||
|
||||
/**
|
||||
* Indicates whether the Border Agent Ephemeral Key feature state is enabled.
|
||||
*/
|
||||
bool IsEphemeralKeyFeatureEnabled(void) { return mIsEphemeralKeyFeatureEnabled; }
|
||||
EphemeralKeyManager &GetEphemeralKeyManager(void) { return mEphemeralKeyManager; }
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
|
||||
@@ -253,16 +299,9 @@ public:
|
||||
const Counters &GetCounters(void) { return mCounters; }
|
||||
|
||||
private:
|
||||
static_assert(kMaxEphemeralKeyLength <= Dtls::Transport::kPskMaxLength,
|
||||
"Max ephemeral key length is larger than max PSK len");
|
||||
|
||||
static constexpr uint16_t kUdpPort = OPENTHREAD_CONFIG_BORDER_AGENT_UDP_PORT;
|
||||
static constexpr uint32_t kKeepAliveTimeout = 50 * 1000; // Timeout to reject a commissioner (in msec)
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
static constexpr uint16_t kMaxEphemeralKeyConnectionAttempts = 10;
|
||||
#endif
|
||||
|
||||
class CoapDtlsSession : public Coap::SecureSession, public Heap::Allocatable<CoapDtlsSession>
|
||||
{
|
||||
friend Heap::Allocatable<CoapDtlsSession>;
|
||||
@@ -288,7 +327,7 @@ private:
|
||||
uint8_t mToken[Coap::Message::kMaxTokenLength];
|
||||
|
||||
private:
|
||||
ForwardContext(CoapDtlsSession &aSesssion, const Coap::Message &aMessage, bool aPetition, bool aSeparate);
|
||||
ForwardContext(CoapDtlsSession &aSession, const Coap::Message &aMessage, bool aPetition, bool aSeparate);
|
||||
};
|
||||
|
||||
CoapDtlsSession(Instance &aInstance, Dtls::Transport &aDtlsTransport);
|
||||
@@ -334,28 +373,15 @@ private:
|
||||
|
||||
static SecureSession *HandleAcceptSession(void *aContext, const Ip6::MessageInfo &aMessageInfo);
|
||||
CoapDtlsSession *HandleAcceptSession(void);
|
||||
static void HandleRemoveSession(void *aContext, SecureSession &aSesssion);
|
||||
void HandleRemoveSession(SecureSession &aSesssion);
|
||||
static void HandleRemoveSession(void *aContext, SecureSession &aSession);
|
||||
void HandleRemoveSession(SecureSession &aSession);
|
||||
|
||||
void HandleSessionConnected(CoapDtlsSession &aSesssion);
|
||||
void HandleSessionDisconnected(CoapDtlsSession &aSesssion, CoapDtlsSession::ConnectEvent aEvent);
|
||||
void HandleCommissionerPetitionAccepted(CoapDtlsSession &aSesssion);
|
||||
void HandleSessionConnected(CoapDtlsSession &aSession);
|
||||
void HandleSessionDisconnected(CoapDtlsSession &aSession, CoapDtlsSession::ConnectEvent aEvent);
|
||||
void HandleCommissionerPetitionAccepted(CoapDtlsSession &aSession);
|
||||
|
||||
static Coap::Message::Code CoapCodeFromError(Error aError);
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
void RestartAfterRemovingEphemeralKey(void);
|
||||
void HandleEphemeralKeyTimeout(void);
|
||||
void InvokeEphemeralKeyCallback(void);
|
||||
static void HandleDtlsTransportClosed(void *aContext);
|
||||
void HandleDtlsTransportClosed(void);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
using EphemeralKeyTimer = TimerMilliIn<BorderAgent, &BorderAgent::HandleEphemeralKeyTimeout>;
|
||||
using EphemeralKeyTask = TaskletIn<BorderAgent, &BorderAgent::InvokeEphemeralKeyCallback>;
|
||||
#endif
|
||||
|
||||
State mState;
|
||||
Dtls::Transport mDtlsTransport;
|
||||
CoapDtlsSession *mCoapDtlsSession;
|
||||
@@ -364,13 +390,7 @@ private:
|
||||
bool mIdInitialized;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
||||
bool mIsEphemeralKeyFeatureEnabled : 1;
|
||||
bool mUsingEphemeralKey : 1;
|
||||
bool mDidConnectWithEphemeralKey : 1;
|
||||
uint16_t mOldUdpPort;
|
||||
EphemeralKeyTimer mEphemeralKeyTimer;
|
||||
EphemeralKeyTask mEphemeralKeyTask;
|
||||
Callback<EphemeralKeyCallback> mEphemeralKeyCallback;
|
||||
EphemeralKeyManager mEphemeralKeyManager;
|
||||
#endif
|
||||
Counters mCounters;
|
||||
};
|
||||
@@ -380,6 +400,7 @@ DeclareTmfHandler(BorderAgent, kUriRelayRx);
|
||||
} // namespace MeshCoP
|
||||
|
||||
DefineCoreType(otBorderAgentId, MeshCoP::BorderAgent::Id);
|
||||
DefineMapEnum(otBorderAgentEphemeralKeyState, MeshCoP::BorderAgent::State);
|
||||
|
||||
} // namespace ot
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
namespace ot {
|
||||
namespace Nexus {
|
||||
|
||||
using BorderAgent = MeshCoP::BorderAgent;
|
||||
|
||||
void TestBorderAgent(void)
|
||||
{
|
||||
Core nexus;
|
||||
@@ -65,15 +67,15 @@ void TestBorderAgent(void)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Check Border Agent initial state");
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateStarted);
|
||||
|
||||
SuccessOrQuit(node0.Get<Ip6::Filter>().AddUnsecurePort(node0.Get<MeshCoP::BorderAgent>().GetUdpPort()));
|
||||
SuccessOrQuit(node0.Get<Ip6::Filter>().AddUnsecurePort(node0.Get<BorderAgent>().GetUdpPort()));
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Establish a DTLS connection to Border Agent");
|
||||
|
||||
sockAddr.SetAddress(node0.Get<Mle::Mle>().GetLinkLocalAddress());
|
||||
sockAddr.SetPort(node0.Get<MeshCoP::BorderAgent>().GetUdpPort());
|
||||
sockAddr.SetPort(node0.Get<BorderAgent>().GetUdpPort());
|
||||
|
||||
node0.Get<KeyManager>().GetPskc(pskc);
|
||||
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SetPsk(pskc.m8, Pskc::kSize));
|
||||
@@ -85,7 +87,8 @@ void TestBorderAgent(void)
|
||||
|
||||
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateConnected);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateConnected);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mPskcSecureSessionSuccesses == 1);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Disconnect from candidate side");
|
||||
@@ -95,7 +98,7 @@ void TestBorderAgent(void)
|
||||
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateStarted);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Establish a secure connection again");
|
||||
@@ -107,7 +110,8 @@ void TestBorderAgent(void)
|
||||
|
||||
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateConnected);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateConnected);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mPskcSecureSessionSuccesses == 2);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Send `Commissioner Petition` TMF command to become full commissioner");
|
||||
@@ -119,14 +123,17 @@ void TestBorderAgent(void)
|
||||
|
||||
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateAccepted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateAccepted);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mPskcSecureSessionSuccesses == 2);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mPskcCommissionerPetitions == 1);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Send `Commissioner Keep Alive` and check timeout behavior");
|
||||
|
||||
nexus.AdvanceTime(30 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateAccepted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateAccepted);
|
||||
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
|
||||
message = node1.Get<Tmf::SecureAgent>().NewPriorityConfirmablePostMessage(kUriCommissionerKeepAlive);
|
||||
@@ -139,14 +146,14 @@ void TestBorderAgent(void)
|
||||
|
||||
nexus.AdvanceTime(49 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateAccepted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateAccepted);
|
||||
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
|
||||
Log(" Wait for additional 5 seconds (ensuring TIMEOUT_LEAD_PET and session disconnect guard time expires)");
|
||||
|
||||
nexus.AdvanceTime(5 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -156,7 +163,7 @@ void TestBorderAgent(void)
|
||||
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateConnected);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateConnected);
|
||||
|
||||
message = node1.Get<Tmf::SecureAgent>().NewPriorityConfirmablePostMessage(kUriCommissionerPetition);
|
||||
VerifyOrQuit(message != nullptr);
|
||||
@@ -165,7 +172,10 @@ void TestBorderAgent(void)
|
||||
|
||||
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateAccepted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateAccepted);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mPskcSecureSessionSuccesses == 3);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mPskcCommissionerPetitions == 2);
|
||||
}
|
||||
|
||||
static bool sEphemeralKeyCallbackCalled = false;
|
||||
@@ -177,22 +187,27 @@ void HandleEphemeralKeyChange(void *aContext)
|
||||
VerifyOrQuit(aContext != nullptr);
|
||||
node = reinterpret_cast<Node *>(aContext);
|
||||
|
||||
Log(" EphemeralKeyCallback() active:%u connected:%u", node->Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive(),
|
||||
node->Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateConnected);
|
||||
Log(" EphemeralKeyCallback() state:%s",
|
||||
BorderAgent::EphemeralKeyManager::StateToString(node->Get<BorderAgent::EphemeralKeyManager>().GetState()));
|
||||
sEphemeralKeyCallbackCalled = true;
|
||||
}
|
||||
|
||||
void TestBorderAgentEphemeralKey(void)
|
||||
{
|
||||
static const char kEphemeralKey[] = "nexus1234";
|
||||
static const char kEphemeralKey[] = "nexus1234";
|
||||
static const char kTooShortEphemeralKey[] = "abcde";
|
||||
static const char kTooLongEphemeralKey[] = "012345678901234567890123456789012";
|
||||
|
||||
static constexpr uint16_t kEphemeralKeySize = sizeof(kEphemeralKey) - 1;
|
||||
static constexpr uint16_t kUdpPort = 49155;
|
||||
|
||||
Core nexus;
|
||||
Node &node0 = nexus.CreateNode();
|
||||
Node &node1 = nexus.CreateNode();
|
||||
Ip6::SockAddr sockAddr;
|
||||
Coap::Message *message;
|
||||
Core nexus;
|
||||
Node &node0 = nexus.CreateNode();
|
||||
Node &node1 = nexus.CreateNode();
|
||||
Node &node2 = nexus.CreateNode();
|
||||
Ip6::SockAddr sockAddr;
|
||||
Ip6::SockAddr baSockAddr;
|
||||
Pskc pskc;
|
||||
|
||||
Log("------------------------------------------------------------------------------------------------------");
|
||||
Log("TestBorderAgentEphemeralKey");
|
||||
@@ -201,7 +216,7 @@ void TestBorderAgentEphemeralKey(void)
|
||||
|
||||
// Form the topology:
|
||||
// - node0 leader acting as Border Agent,
|
||||
// - node1 staying disconnected (acting as candidate)
|
||||
// - node1 and node2 staying disconnected (acting as candidate)
|
||||
|
||||
node0.Form();
|
||||
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
|
||||
@@ -211,34 +226,51 @@ void TestBorderAgentEphemeralKey(void)
|
||||
node1.Get<Mac::Mac>().SetPanId(node0.Get<Mac::Mac>().GetPanId());
|
||||
node1.Get<ThreadNetif>().Up();
|
||||
|
||||
SuccessOrQuit(node2.Get<Mac::Mac>().SetPanChannel(node0.Get<Mac::Mac>().GetPanChannel()));
|
||||
node2.Get<Mac::Mac>().SetPanId(node0.Get<Mac::Mac>().GetPanId());
|
||||
node2.Get<ThreadNetif>().Up();
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Check Border Agent ephemeral key counter's initial value");
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 0);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcSecureSessionSuccesses == 0);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationTimeouts == 0);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationDisconnects == 0);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationMaxAttempts == 0);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationClears == 0);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcInvalidArgsErrors == 0);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcInvalidBaStateErrors == 0);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Check Border Agent ephemeral key feature enabled");
|
||||
|
||||
node0.Get<MeshCoP::BorderAgent>().SetEphemeralKeyFeatureEnabled(false);
|
||||
VerifyOrQuit(!node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyFeatureEnabled());
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().SetEphemeralKey(kEphemeralKey, /* aTimeout */ 0, kUdpPort) ==
|
||||
kErrorNotCapable);
|
||||
node0.Get<MeshCoP::BorderAgent::EphemeralKeyManager>().SetEnabled(false);
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateDisabled);
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent::EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0,
|
||||
kUdpPort) == kErrorInvalidState);
|
||||
|
||||
node0.Get<MeshCoP::BorderAgent>().SetEphemeralKeyFeatureEnabled(true);
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyFeatureEnabled());
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcInvalidBaStateErrors == 1);
|
||||
|
||||
node0.Get<MeshCoP::BorderAgent::EphemeralKeyManager>().SetEnabled(true);
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStopped);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Check Border Agent ephemeral key initial state");
|
||||
|
||||
sEphemeralKeyCallbackCalled = false;
|
||||
VerifyOrQuit(!node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(!sEphemeralKeyCallbackCalled);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Set and start ephemeral key on Border Agent");
|
||||
|
||||
node0.Get<MeshCoP::BorderAgent>().SetEphemeralKeyCallback(HandleEphemeralKeyChange, &node0);
|
||||
node0.Get<BorderAgent::EphemeralKeyManager>().SetCallback(HandleEphemeralKeyChange, &node0);
|
||||
|
||||
SuccessOrQuit(node0.Get<MeshCoP::BorderAgent>().SetEphemeralKey(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
||||
SuccessOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetUdpPort() == kUdpPort);
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 1);
|
||||
|
||||
SuccessOrQuit(node0.Get<Ip6::Filter>().AddUnsecurePort(kUdpPort));
|
||||
|
||||
@@ -261,8 +293,11 @@ void TestBorderAgentEphemeralKey(void)
|
||||
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateConnected);
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateConnected);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 1);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcSecureSessionSuccesses == 1);
|
||||
|
||||
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -275,22 +310,23 @@ void TestBorderAgentEphemeralKey(void)
|
||||
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateStarted);
|
||||
|
||||
VerifyOrQuit(!node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStopped);
|
||||
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 1);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcSecureSessionSuccesses == 1);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
||||
|
||||
nexus.AdvanceTime(10 * Time::kOneSecondInMsec);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Start using ephemeral key again with short timeout (20 seconds) and establish a connection");
|
||||
|
||||
SuccessOrQuit(
|
||||
node0.Get<MeshCoP::BorderAgent>().SetEphemeralKey(kEphemeralKey, 20 * Time::kOneSecondInMsec, kUdpPort));
|
||||
node0.Get<BorderAgent::EphemeralKeyManager>().Start(kEphemeralKey, 20 * Time::kOneSecondInMsec, kUdpPort));
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetUdpPort() == kUdpPort);
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
||||
|
||||
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Open());
|
||||
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
||||
@@ -298,8 +334,11 @@ void TestBorderAgentEphemeralKey(void)
|
||||
nexus.AdvanceTime(2 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateConnected);
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateConnected);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 2);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcSecureSessionSuccesses == 2);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
||||
|
||||
Log(" Check the ephemeral key timeout behavior");
|
||||
|
||||
@@ -307,33 +346,41 @@ void TestBorderAgentEphemeralKey(void)
|
||||
nexus.AdvanceTime(25 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(!node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStopped);
|
||||
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 2);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcSecureSessionSuccesses == 2);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationTimeouts == 1);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Start using ephemeral key without any candidate connecting, check timeout");
|
||||
|
||||
SuccessOrQuit(node0.Get<MeshCoP::BorderAgent>().SetEphemeralKey(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
||||
SuccessOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetUdpPort() == kUdpPort);
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
||||
|
||||
Log(" Wait more than 120 seconds (default ephemeral key timeout)");
|
||||
sEphemeralKeyCallbackCalled = false;
|
||||
nexus.AdvanceTime(122 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(!node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStopped);
|
||||
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 3);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcSecureSessionSuccesses == 2);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationTimeouts == 2);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Check that ephemeral key use is stopped after max failed connection attempts");
|
||||
|
||||
SuccessOrQuit(node0.Get<MeshCoP::BorderAgent>().SetEphemeralKey(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
||||
SuccessOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
||||
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() == MeshCoP::BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetUdpPort() == kUdpPort);
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
||||
|
||||
SuccessOrQuit(
|
||||
node1.Get<Tmf::SecureAgent>().SetPsk(reinterpret_cast<const uint8_t *>(kEphemeralKey), kEphemeralKeySize - 2));
|
||||
@@ -347,8 +394,7 @@ void TestBorderAgentEphemeralKey(void)
|
||||
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().GetState() != MeshCoP::BorderAgent::kStateConnected);
|
||||
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStarted);
|
||||
}
|
||||
|
||||
Log(" Attempt 10 (final attempt) to connect with the wrong key, check that ephemeral key use is stopped");
|
||||
@@ -358,8 +404,146 @@ void TestBorderAgentEphemeralKey(void)
|
||||
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(!node0.Get<MeshCoP::BorderAgent>().IsEphemeralKeyActive());
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStopped);
|
||||
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 4);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcSecureSessionSuccesses == 2);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationTimeouts == 2);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationMaxAttempts == 1);
|
||||
|
||||
node1.Get<Tmf::SecureAgent>().Close();
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Validate that disabling ephemeral key will stop and disconnect an active session");
|
||||
|
||||
SuccessOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
||||
|
||||
SuccessOrQuit(
|
||||
node1.Get<Tmf::SecureAgent>().SetPsk(reinterpret_cast<const uint8_t *>(kEphemeralKey), kEphemeralKeySize));
|
||||
|
||||
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Open());
|
||||
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
||||
|
||||
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateConnected);
|
||||
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
||||
|
||||
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
||||
|
||||
sEphemeralKeyCallbackCalled = false;
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateConnected);
|
||||
node0.Get<BorderAgent::EphemeralKeyManager>().SetEnabled(false);
|
||||
|
||||
nexus.AdvanceTime(0);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateDisabled);
|
||||
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
||||
|
||||
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
||||
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 5);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcSecureSessionSuccesses == 3);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationTimeouts == 2);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationMaxAttempts == 1);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationClears == 1);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Check ephemeral key can be used along with PSKc");
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateStarted);
|
||||
SuccessOrQuit(node0.Get<Ip6::Filter>().AddUnsecurePort(node0.Get<BorderAgent>().GetUdpPort()));
|
||||
|
||||
node0.Get<BorderAgent::EphemeralKeyManager>().SetEnabled(true);
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStopped);
|
||||
|
||||
SuccessOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStarted);
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
||||
|
||||
Log(" Establish a secure session using PSKc (from node2)");
|
||||
|
||||
baSockAddr.SetAddress(node0.Get<Mle::Mle>().GetLinkLocalAddress());
|
||||
baSockAddr.SetPort(node0.Get<BorderAgent>().GetUdpPort());
|
||||
|
||||
node0.Get<KeyManager>().GetPskc(pskc);
|
||||
SuccessOrQuit(node2.Get<Tmf::SecureAgent>().SetPsk(pskc.m8, Pskc::kSize));
|
||||
SuccessOrQuit(node2.Get<Tmf::SecureAgent>().Open());
|
||||
SuccessOrQuit(node2.Get<Tmf::SecureAgent>().Connect(baSockAddr));
|
||||
|
||||
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(node2.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateConnected);
|
||||
|
||||
Log(" Establish a secure session using ephemeral key (from node1)");
|
||||
|
||||
node1.Get<Tmf::SecureAgent>().Close();
|
||||
SuccessOrQuit(
|
||||
node1.Get<Tmf::SecureAgent>().SetPsk(reinterpret_cast<const uint8_t *>(kEphemeralKey), kEphemeralKeySize));
|
||||
|
||||
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Open());
|
||||
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
||||
|
||||
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateConnected);
|
||||
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
||||
|
||||
Log(" Stop the secure session using ephemeral key");
|
||||
|
||||
node0.Get<BorderAgent::EphemeralKeyManager>().Stop();
|
||||
|
||||
sEphemeralKeyCallbackCalled = false;
|
||||
|
||||
nexus.AdvanceTime(0);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStopped);
|
||||
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 6);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcSecureSessionSuccesses == 4);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationTimeouts == 2);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationMaxAttempts == 1);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcDeactivationClears == 2);
|
||||
|
||||
Log(" Check the BA session using PSKc is still connected");
|
||||
|
||||
VerifyOrQuit(node2.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateConnected);
|
||||
|
||||
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
||||
VerifyOrQuit(node2.Get<Tmf::SecureAgent>().IsConnected());
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().GetState() == BorderAgent::kStateStopped);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetState() == BorderAgent::kStateConnected);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Check proper error is returned with invalid ephemeral key (too short or long)");
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().Start(kTooShortEphemeralKey, /* aTimeout */ 0,
|
||||
kUdpPort) == kErrorInvalidArgs);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 6);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcInvalidArgsErrors == 1);
|
||||
|
||||
VerifyOrQuit(node0.Get<BorderAgent::EphemeralKeyManager>().Start(kTooLongEphemeralKey, /* aTimeout */ 0,
|
||||
kUdpPort) == kErrorInvalidArgs);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcActivations == 6);
|
||||
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcInvalidArgsErrors == 2);
|
||||
}
|
||||
|
||||
} // namespace Nexus
|
||||
|
||||
@@ -181,12 +181,6 @@ expect ": InvalidState"
|
||||
send "ba port\n"
|
||||
expect "Done"
|
||||
|
||||
send "ba state\n"
|
||||
expect "Done"
|
||||
|
||||
send "ba disconnect\n"
|
||||
expect "Done"
|
||||
|
||||
send "prefix meshlocal fd00:dead:beef:cafe::/96\n"
|
||||
expect_line "Error 7: InvalidArgs"
|
||||
send "prefix meshlocal fd00:dead:beef:cafe::/64\n"
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2024, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
import logging
|
||||
import unittest
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
|
||||
# Test description:
|
||||
# This test verifies the counters of ephemeral key activations/deactivations.
|
||||
#
|
||||
# Topology:
|
||||
# --------------
|
||||
# |
|
||||
# BR1
|
||||
#
|
||||
|
||||
BR1 = 1
|
||||
|
||||
|
||||
class EphemeralKeyCountersTest(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
BR1: {
|
||||
'name': 'BR_1',
|
||||
'is_otbr': True,
|
||||
'version': '1.4',
|
||||
'network_name': 'ot-br1',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
br1 = self.nodes[BR1]
|
||||
|
||||
counters = br1.get_border_agent_counters()
|
||||
self.assertEqual(counters['epskcActivation'], 0)
|
||||
self.assertEqual(counters['epskcApiDeactivation'], 0)
|
||||
self.assertEqual(counters['epskcTimeoutDeactivation'], 0)
|
||||
self.assertEqual(counters['epskcMaxAttemptDeactivation'], 0)
|
||||
self.assertEqual(counters['epskcDisconnectDeactivation'], 0)
|
||||
self.assertEqual(counters['epskcInvalidBaStateError'], 0)
|
||||
self.assertEqual(counters['epskcInvalidArgsError'], 0)
|
||||
self.assertEqual(counters['epskcStartSecureSessionError'], 0)
|
||||
self.assertEqual(counters['epskcSecureSessionSuccess'], 0)
|
||||
self.assertEqual(counters['epskcSecureSessionFailure'], 0)
|
||||
self.assertEqual(counters['epskcCommissionerPetition'], 0)
|
||||
self.assertEqual(counters['pskcSecureSessionSuccess'], 0)
|
||||
self.assertEqual(counters['pskcSecureSessionFailure'], 0)
|
||||
self.assertEqual(counters['pskcCommissionerPetition'], 0)
|
||||
self.assertEqual(counters['mgmtActiveGet'], 0)
|
||||
self.assertEqual(counters['mgmtPendingGet'], 0)
|
||||
|
||||
# activate epskc before border agent is up returns an error
|
||||
br1.set_epskc('123456789')
|
||||
|
||||
counters = br1.get_border_agent_counters()
|
||||
self.assertEqual(counters['epskcActivation'], 0)
|
||||
self.assertEqual(counters['epskcInvalidBaStateError'], 1)
|
||||
|
||||
br1.set_active_dataset(updateExisting=True, network_name='ot-br1')
|
||||
br1.start()
|
||||
self.simulator.go(config.BORDER_ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual('leader', br1.get_state())
|
||||
|
||||
# activate epskc and let it timeout
|
||||
br1.set_epskc('123456789', 10)
|
||||
self.simulator.go(1)
|
||||
|
||||
counters = br1.get_border_agent_counters()
|
||||
self.assertEqual(counters['epskcActivation'], 1)
|
||||
self.assertEqual(counters['epskcApiDeactivation'], 0)
|
||||
self.assertEqual(counters['epskcTimeoutDeactivation'], 1)
|
||||
|
||||
# activate epskc and clear it
|
||||
br1.set_epskc('123456789', 10000)
|
||||
self.simulator.go(1)
|
||||
br1.clear_epskc()
|
||||
|
||||
counters = br1.get_border_agent_counters()
|
||||
self.assertEqual(counters['epskcActivation'], 2)
|
||||
self.assertEqual(counters['epskcApiDeactivation'], 1)
|
||||
self.assertEqual(counters['epskcTimeoutDeactivation'], 1)
|
||||
|
||||
# set epskc with invalid passcode
|
||||
br1.set_epskc('123')
|
||||
self.simulator.go(1)
|
||||
|
||||
counters = br1.get_border_agent_counters()
|
||||
self.assertEqual(counters['epskcActivation'], 2)
|
||||
self.assertEqual(counters['epskcApiDeactivation'], 1)
|
||||
self.assertEqual(counters['epskcTimeoutDeactivation'], 1)
|
||||
self.assertEqual(counters['epskcInvalidArgsError'], 1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -106,13 +106,13 @@ class PublishMeshCopService(thread_cert.TestCase):
|
||||
lifetime = 500_000
|
||||
ephemeral_key = br1.activate_ephemeral_key_mode(lifetime)
|
||||
self.assertEqual(len(ephemeral_key), 9)
|
||||
self.assertEqual(br1.get_ephemeral_key_state(), 'active')
|
||||
self.assertEqual(br1.get_ephemeral_key_state(), 'Started')
|
||||
# check Meshcop-e service
|
||||
self.check_meshcop_e_service(host, True)
|
||||
|
||||
# deactivate ePSKc mode in force
|
||||
br1.deactivate_ephemeral_key_mode(retain_active_session=False)
|
||||
self.assertEqual(br1.get_ephemeral_key_state(), 'inactive')
|
||||
self.assertEqual(br1.get_ephemeral_key_state(), 'Stopped')
|
||||
self.simulator.go(10)
|
||||
# check Meshcop-e service
|
||||
self.check_meshcop_e_service(host, False)
|
||||
@@ -121,13 +121,13 @@ class PublishMeshCopService(thread_cert.TestCase):
|
||||
lifetime = 0
|
||||
ephemeral_key = br1.activate_ephemeral_key_mode(lifetime)
|
||||
self.assertEqual(len(ephemeral_key), 9)
|
||||
self.assertEqual(br1.get_ephemeral_key_state(), 'active')
|
||||
self.assertEqual(br1.get_ephemeral_key_state(), 'Started')
|
||||
# check Meshcop-e service
|
||||
self.check_meshcop_e_service(host, True)
|
||||
|
||||
# deactivate ePSKc mode NOT in force
|
||||
br1.deactivate_ephemeral_key_mode(retain_active_session=True)
|
||||
self.assertEqual(br1.get_ephemeral_key_state(), 'inactive')
|
||||
self.assertEqual(br1.get_ephemeral_key_state(), 'Stopped')
|
||||
self.simulator.go(10)
|
||||
# check Meshcop-e service
|
||||
self.check_meshcop_e_service(host, False)
|
||||
|
||||
@@ -1456,16 +1456,6 @@ class NodeImpl:
|
||||
self.send_command(cmd)
|
||||
return int(self._expect_command_output()[0])
|
||||
|
||||
def set_epskc(self, keystring: str, timeout=120000, port=0):
|
||||
cmd = 'ba ephemeralkey set ' + keystring + ' ' + str(timeout) + ' ' + str(port)
|
||||
self.send_command(cmd)
|
||||
self._expect(r"(Done|Error .*)")
|
||||
|
||||
def clear_epskc(self):
|
||||
cmd = 'ba ephemeralkey clear'
|
||||
self.send_command(cmd)
|
||||
self._expect_done()
|
||||
|
||||
def get_border_agent_counters(self):
|
||||
cmd = 'ba counters'
|
||||
self.send_command(cmd)
|
||||
@@ -1934,7 +1924,7 @@ class NodeImpl:
|
||||
|
||||
def get_ephemeral_key_state(self):
|
||||
cmd = 'ba ephemeralkey'
|
||||
states = [r'inactive', r'active']
|
||||
states = [r'Disabled', r'Stopped', r'Started', r'Connected', r'Accepted']
|
||||
self.send_command(cmd)
|
||||
return self._expect_result(states)
|
||||
|
||||
|
||||
+11
-11
@@ -525,20 +525,20 @@ class Node(object):
|
||||
def ba_get_port(self):
|
||||
return self._cli_single_output('ba port')
|
||||
|
||||
def ba_is_ephemeral_key_feature_enabled(self):
|
||||
return self._cli_single_output('ba ephemeralkey feature')
|
||||
|
||||
def ba_set_ephemeral_key_feature_enabled(self, enable):
|
||||
self._cli_no_output('ba ephemeralkey feature', 'enable' if enable else 'disable')
|
||||
|
||||
def ba_is_ephemeral_key_active(self):
|
||||
def ba_ephemeral_key_get_state(self):
|
||||
return self._cli_single_output('ba ephemeralkey')
|
||||
|
||||
def ba_set_ephemeral_key(self, keystring, timeout=None, port=None):
|
||||
self._cli_no_output('ba ephemeralkey set', keystring, timeout, port)
|
||||
def ba_ephemeral_key_set_enabled(self, enable):
|
||||
self._cli_no_output('ba ephemeralkey', 'enable' if enable else 'disable')
|
||||
|
||||
def ba_clear_ephemeral_key(self):
|
||||
self._cli_no_output('ba ephemeralkey clear')
|
||||
def ba_ephemeral_key_start(self, keystring, timeout=None, port=None):
|
||||
self._cli_no_output('ba ephemeralkey start', keystring, timeout, port)
|
||||
|
||||
def ba_ephemeral_key_stop(self):
|
||||
self._cli_no_output('ba ephemeralkey stop')
|
||||
|
||||
def ba_ephemeral_key_get_port(self):
|
||||
return self._cli_single_output('ba ephemeralkey port')
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# UDP
|
||||
|
||||
@@ -55,41 +55,20 @@ leader.form('ba-ephemeral')
|
||||
|
||||
verify(leader.get_state() == 'leader')
|
||||
|
||||
leader.ba_set_ephemeral_key_feature_enabled(False)
|
||||
verify(leader.ba_is_ephemeral_key_feature_enabled() == 'Disabled')
|
||||
leader.ba_set_ephemeral_key_feature_enabled(True)
|
||||
verify(leader.ba_is_ephemeral_key_feature_enabled() == 'Enabled')
|
||||
leader.ba_ephemeral_key_set_enabled(False)
|
||||
verify(leader.ba_ephemeral_key_get_state() == 'Disabled')
|
||||
leader.ba_ephemeral_key_set_enabled(True)
|
||||
verify(leader.ba_ephemeral_key_get_state() == 'Stopped')
|
||||
|
||||
verify(leader.ba_is_ephemeral_key_active() == 'inactive')
|
||||
|
||||
port = int(leader.ba_get_port())
|
||||
|
||||
leader.ba_set_ephemeral_key('password', 10000, 1234)
|
||||
leader.ba_ephemeral_key_start('password', 10000, 1234)
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
verify(leader.ba_is_ephemeral_key_active() == 'active')
|
||||
verify(int(leader.ba_get_port()) == 1234)
|
||||
verify(leader.ba_ephemeral_key_get_state() == 'Started')
|
||||
verify(int(leader.ba_ephemeral_key_get_port()) == 1234)
|
||||
|
||||
leader.ba_set_ephemeral_key('password2', 200, 45678)
|
||||
|
||||
time.sleep(0.100 / speedup)
|
||||
verify(leader.ba_is_ephemeral_key_active() == 'active')
|
||||
verify(int(leader.ba_get_port()) == 45678)
|
||||
|
||||
time.sleep(0.150 / speedup)
|
||||
verify(leader.ba_is_ephemeral_key_active() == 'inactive')
|
||||
verify(int(leader.ba_get_port()) == port)
|
||||
|
||||
leader.ba_set_ephemeral_key('newkey')
|
||||
verify(leader.ba_is_ephemeral_key_active() == 'active')
|
||||
|
||||
time.sleep(0.1)
|
||||
verify(leader.ba_is_ephemeral_key_active() == 'active')
|
||||
|
||||
leader.ba_clear_ephemeral_key()
|
||||
verify(leader.ba_is_ephemeral_key_active() == 'inactive')
|
||||
verify(int(leader.ba_get_port()) == port)
|
||||
leader.ba_ephemeral_key_stop()
|
||||
verify(leader.ba_ephemeral_key_get_state() == 'Stopped')
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test finished
|
||||
|
||||
Reference in New Issue
Block a user