[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:
Abtin Keshavarzian
2025-02-04 09:34:08 -05:00
committed by GitHub
parent c5458354da
commit bdb394eb3b
16 changed files with 1035 additions and 903 deletions
+128 -130
View File
@@ -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);
/**
* @}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+49 -59
View File
@@ -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
+1 -1
View File
@@ -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
/**
+7
View File
@@ -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
View File
@@ -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
View File
@@ -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
+241 -57
View File
@@ -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
-6
View File
@@ -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)
+1 -11
View File
@@ -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
View File
@@ -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