Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Commit 42c1515

Browse files
emargolisrobszewczyk
authored andcommitted
Implemented PASE Rate Limiter Protocol.
A time-based rate limiter for PASE negotiation attempts is implemented. -- The mechanism limits all PASE attempts to 3 failures within a 15 second period. These parameters are build time defines and can be adjusted for each platform. -- PASE attempts beyond the limit are rejected immediately with a Common:Busy status code. -- For PASE negotiations with key confirmation option enabled: only attempts that failed with key confirmation error are counted. Successful PASE negotiations do not reset the rate limiter. -- For PASE negotiations with key confirmation option disabled: every PASE negotiation, successful or otherwise, is added to the rate limiter. This change addresses CVE security vulnerability: CVE-2019-5035
1 parent 17ed842 commit 42c1515

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

src/lib/core/WeaveConfig.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,37 @@
426426
#endif // WEAVE_CONFIG_USE_MICRO_ECC
427427
#endif // WEAVE_CONFIG_PASE_MESSAGE_PAYLOAD_ALIGNMENT
428428

429+
/**
430+
* @def WEAVE_CONFIG_PASE_RATE_LIMITER_TIMEOUT
431+
*
432+
* @brief
433+
* The amount of time (in milliseconds) in which the Security Manager
434+
* is allowed to have maximum #WEAVE_CONFIG_PASE_RATE_LIMITER_MAX_ATTEMPTS
435+
* counted PASE attempts.
436+
*
437+
*/
438+
#ifndef WEAVE_CONFIG_PASE_RATE_LIMITER_TIMEOUT
439+
#define WEAVE_CONFIG_PASE_RATE_LIMITER_TIMEOUT 15000
440+
#endif // WEAVE_CONFIG_PASE_RATE_LIMITER_TIMEOUT
441+
442+
/**
443+
* @def WEAVE_CONFIG_PASE_RATE_LIMITER_MAX_ATTEMPTS
444+
*
445+
* @brief
446+
* The maximum number of PASE attempts after which the
447+
* next PASE session establishment attempt will be allowed
448+
* only after #WEAVE_CONFIG_PASE_RATE_LIMITER_TIMEOUT expires.
449+
* * For PASE negotiations with key confirmation option enabled:
450+
* only attempts that failed with key confirmation error are counted.
451+
* Successful PASE negotiations do not reset the rate limiter.
452+
* * For PASE negotiations with key confirmation option disabled:
453+
* every PASE negotiation, successful or otherwise, is added
454+
* to the rate limiter.
455+
*
456+
*/
457+
#ifndef WEAVE_CONFIG_PASE_RATE_LIMITER_MAX_ATTEMPTS
458+
#define WEAVE_CONFIG_PASE_RATE_LIMITER_MAX_ATTEMPTS 3
459+
#endif // WEAVE_CONFIG_PASE_RATE_LIMITER_MAX_ATTEMPTS
429460

430461
/**
431462
* @name Weave Security Manager Memory Management Configuration

src/lib/core/WeaveSecurityMgr.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ WEAVE_ERROR WeaveSecurityManager::Init(WeaveExchangeManager& aExchangeMgr, Syste
9898
#if WEAVE_CONFIG_ENABLE_PASE_INITIATOR || WEAVE_CONFIG_ENABLE_PASE_RESPONDER
9999
mPASEEngine = NULL;
100100
#endif
101+
#if WEAVE_CONFIG_ENABLE_PASE_RESPONDER
102+
mPASERateLimiterTimeout = 0;
103+
mPASERateLimiterCount = 0;
104+
#endif
101105
#if WEAVE_CONFIG_ENABLE_CASE_INITIATOR || WEAVE_CONFIG_ENABLE_CASE_RESPONDER
102106
mCASEEngine = NULL;
103107
mDefaultAuthDelegate = NULL;
@@ -223,6 +227,14 @@ void WeaveSecurityManager::HandleUnsolicitedMessage(ExchangeContext *ec, const I
223227
// PASE is not supported over WRMP.
224228
VerifyOrExit(ec->Con != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
225229

230+
uint64_t nowTimeMS = System::Layer::GetClock_MonotonicMS();
231+
232+
// PASE rate limiter.
233+
// Reject the request if too many PASE attempts in a given time period.
234+
VerifyOrExit(secMgr->mPASERateLimiterCount < WEAVE_CONFIG_PASE_RATE_LIMITER_MAX_ATTEMPTS ||
235+
secMgr->mPASERateLimiterTimeout < nowTimeMS,
236+
err = WEAVE_ERROR_RATE_LIMIT_EXCEEDED);
237+
226238
secMgr->HandlePASESessionStart(ec, pktInfo, msgInfo, msgBuf);
227239
msgBuf = NULL;
228240
#else
@@ -2853,6 +2865,33 @@ void WeaveSecurityManager::HandleMsgCounterSyncRespMsg(WeaveMessageInfo *msgInfo
28532865

28542866
#endif // WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC
28552867

2868+
#if WEAVE_CONFIG_ENABLE_PASE_RESPONDER
2869+
void WeaveSecurityManager::UpdatePASERateLimiter(WEAVE_ERROR err)
2870+
{
2871+
// Update PASE rate limiter parameters in the following cases:
2872+
// -- PASE with key confirmation: count only PASE attempts that fail with key confirmation error.
2873+
// -- PASE without key confirmation: every PASE attempt counts as failure.
2874+
if (State == kState_PASEInProgress && mPASEEngine->IsResponder() &&
2875+
((mPASEEngine->PerformKeyConfirmation && err == WEAVE_ERROR_KEY_CONFIRMATION_FAILED) ||
2876+
(!mPASEEngine->PerformKeyConfirmation && err == WEAVE_NO_ERROR)))
2877+
{
2878+
uint64_t nowTimeMS = System::Layer::GetClock_MonotonicMS();
2879+
2880+
// Reset PASE rate limiter parameters if timeout expired.
2881+
if (nowTimeMS > mPASERateLimiterTimeout)
2882+
{
2883+
mPASERateLimiterTimeout = nowTimeMS + WEAVE_CONFIG_PASE_RATE_LIMITER_TIMEOUT;
2884+
mPASERateLimiterCount = 1;
2885+
}
2886+
// Otherwise, increment PASE rate limiter counter.
2887+
else
2888+
{
2889+
mPASERateLimiterCount++;
2890+
}
2891+
}
2892+
}
2893+
#endif // WEAVE_CONFIG_ENABLE_PASE_RESPONDER
2894+
28562895
WEAVE_ERROR WeaveSecurityManager::HandleSessionEstablished(void)
28572896
{
28582897
WEAVE_ERROR err = WEAVE_NO_ERROR;
@@ -2892,6 +2931,10 @@ WEAVE_ERROR WeaveSecurityManager::HandleSessionEstablished(void)
28922931
// Form the key auth mode based on the password source.
28932932
authMode = PASEAuthMode(mPASEEngine->PwSource);
28942933

2934+
#if WEAVE_CONFIG_ENABLE_PASE_RESPONDER
2935+
UpdatePASERateLimiter(WEAVE_NO_ERROR);
2936+
#endif
2937+
28952938
break;
28962939
#endif
28972940

@@ -2980,6 +3023,10 @@ void WeaveSecurityManager::HandleSessionError(WEAVE_ERROR err, PacketBuffer* sta
29803023
StatusReport rcvdStatusReport;
29813024
StatusReport *statusReportPtr = NULL;
29823025

3026+
#if WEAVE_CONFIG_ENABLE_PASE_RESPONDER
3027+
UpdatePASERateLimiter(err);
3028+
#endif
3029+
29833030
// If a status report was received from the peer, parse it and arrange to pass it
29843031
// to the callbacks.
29853032
if (err == WEAVE_ERROR_STATUS_REPORT_RECEIVED)

src/lib/core/WeaveSecurityMgr.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,11 @@ class NL_DLL_EXPORT WeaveSecurityManager
405405
void *mStartSecureSession_ReqState;
406406
void *mStartKeyExport_ReqState;
407407
};
408+
#if WEAVE_CONFIG_ENABLE_PASE_RESPONDER
409+
uint32_t mPASERateLimiterTimeout;
410+
uint8_t mPASERateLimiterCount;
411+
void UpdatePASERateLimiter(WEAVE_ERROR err);
412+
#endif
408413
#if WEAVE_CONFIG_ENABLE_CASE_INITIATOR || WEAVE_CONFIG_ENABLE_CASE_RESPONDER
409414
WeaveCASEAuthDelegate *mDefaultAuthDelegate;
410415
#endif

0 commit comments

Comments
 (0)