Skip to content

Commit d495974

Browse files
committed
rekey: trigger highwater on per-key packet count
- Track txMsgCount/rxMsgCount per key epoch and reset on NEW_KEYS; seq/peerSeq still wrap freely per RFC 4253 Sec 6.4. - Extend HighwaterCheck to fire highwaterCb when packet count crosses msgHighwaterMark (default 2^31, RFC 4344 Sec 3.1). - Add wolfSSH_CTX_SetMsgHighwater / SetMsgHighwater / GetMsgHighwater. Issue: F-246
1 parent 834e60f commit d495974

4 files changed

Lines changed: 94 additions & 10 deletions

File tree

src/internal.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@
188188
Set the number of Miller-Rabin rounds used when the client checks the
189189
server's prime group when using GEX key exchange. The default is 8. More
190190
rounds are better, but also takes a lot longer.
191+
WOLFSSH_DEFAULT_MSG_HIGHWATER_MARK
192+
Set the default value for the number of messages to send or receive before
193+
calling the highwater callback function. By default this forces a rekey.
191194
*/
192195

193196
static const char sshProtoIdStr[] = "SSH-2.0-wolfSSHv"
@@ -544,7 +547,10 @@ static int HashUpdate(wc_HashAlg* hash, enum wc_HashType type,
544547
static INLINE int HighwaterCheck(WOLFSSH* ssh, byte side)
545548
{
546549
int ret = WS_SUCCESS;
550+
int fire = 0;
547551

552+
/* RFC 4253 Sec 9: bound bytes per key (txCount/rxCount reset on rekey)
553+
* to limit cipher keystream/IV exhaustion under a single key. */
548554
if (!ssh->highwaterFlag && ssh->highwaterMark &&
549555
(ssh->txCount >= ssh->highwaterMark ||
550556
ssh->rxCount >= ssh->highwaterMark)) {
@@ -553,10 +559,26 @@ static INLINE int HighwaterCheck(WOLFSSH* ssh, byte side)
553559
(side == WOLFSSH_HWSIDE_TRANSMIT) ? "Transmit" : "Receive");
554560

555561
ssh->highwaterFlag = 1;
562+
fire = 1;
563+
}
564+
565+
/* RFC 4344 Sec 3.1: bound packets per key (txMsgCount/rxMsgCount reset on
566+
* rekey) to limit cipher/IV exhaustion under a single key; this is not a
567+
* guard for the absolute SSH sequence number, which never resets. */
568+
if (!ssh->msgHighwaterFlag && ssh->msgHighwaterMark &&
569+
(ssh->txMsgCount >= ssh->msgHighwaterMark ||
570+
ssh->rxMsgCount >= ssh->msgHighwaterMark)) {
571+
572+
WLOG(WS_LOG_DEBUG, "%s over msg high water mark",
573+
(side == WOLFSSH_HWSIDE_TRANSMIT) ? "Transmit" : "Receive");
556574

557-
if (ssh->ctx->highwaterCb)
558-
ret = ssh->ctx->highwaterCb(side, ssh->highwaterCtx);
575+
ssh->msgHighwaterFlag = 1;
576+
fire = 1;
559577
}
578+
579+
if (fire && ssh->ctx->highwaterCb)
580+
ret = ssh->ctx->highwaterCb(side, ssh->highwaterCtx);
581+
560582
return ret;
561583
}
562584

@@ -1025,6 +1047,7 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap)
10251047
ctx->ioSendCb = wsEmbedSend;
10261048
#endif /* WOLFSSH_USER_IO */
10271049
ctx->highwaterMark = DEFAULT_HIGHWATER_MARK;
1050+
ctx->msgHighwaterMark = WOLFSSH_DEFAULT_MSG_HIGHWATER_MARK;
10281051
ctx->highwaterCb = wsHighwater;
10291052
#if defined(WOLFSSH_SCP) && !defined(WOLFSSH_SCP_USER_CALLBACKS)
10301053
ctx->scpRecvCb = wsScpRecvCallback;
@@ -1227,6 +1250,7 @@ WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx)
12271250
ssh->ioReadCtx = &ssh->rfd; /* prevent invalid access if not correctly */
12281251
ssh->ioWriteCtx = &ssh->wfd; /* set */
12291252
ssh->highwaterMark = ctx->highwaterMark;
1253+
ssh->msgHighwaterMark = ctx->msgHighwaterMark;
12301254
ssh->highwaterCtx = (void*)ssh;
12311255
ssh->reqSuccessCtx = (void*)ssh;
12321256
ssh->fs = NULL;
@@ -6284,7 +6308,9 @@ static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
62846308

62856309
if (ret == WS_SUCCESS) {
62866310
ssh->rxCount = 0;
6311+
ssh->rxMsgCount = 0;
62876312
ssh->highwaterFlag = 0;
6313+
ssh->msgHighwaterFlag = 0;
62886314

62896315
/* Clear peer is keying flag */
62906316
ssh->isKeying &= ~WOLFSSH_PEER_IS_KEYING;
@@ -10162,6 +10188,7 @@ static int DoPacket(WOLFSSH* ssh, byte* bufferConsumed)
1016210188
idx += padSz;
1016310189
ssh->inputBuffer.idx = idx;
1016410190
ssh->peerSeq++;
10191+
ssh->rxMsgCount++;
1016510192
*bufferConsumed = 1;
1016610193
}
1016710194

@@ -10991,6 +11018,7 @@ static int BundlePacket(WOLFSSH* ssh)
1099111018

1099211019
if (ret == WS_SUCCESS) {
1099311020
ssh->seq++;
11021+
ssh->txMsgCount++;
1099411022
ssh->outputBuffer.length = idx;
1099511023
}
1099611024
else {
@@ -13301,6 +13329,7 @@ int SendNewKeys(WOLFSSH* ssh)
1330113329

1330213330
if (ret == WS_SUCCESS) {
1330313331
ssh->txCount = 0;
13332+
ssh->txMsgCount = 0;
1330413333
}
1330513334

1330613335
if (ret == WS_SUCCESS) {

src/ssh.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,45 @@ word32 wolfSSH_GetHighwater(WOLFSSH* ssh)
267267
}
268268

269269

270+
int wolfSSH_CTX_SetMsgHighwater(WOLFSSH_CTX* ctx, word32 highwater)
271+
{
272+
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_CTX_SetMsgHighwater()");
273+
274+
if (ctx) {
275+
ctx->msgHighwaterMark = highwater;
276+
277+
return WS_SUCCESS;
278+
}
279+
280+
return WS_BAD_ARGUMENT;
281+
}
282+
283+
284+
int wolfSSH_SetMsgHighwater(WOLFSSH* ssh, word32 highwater)
285+
{
286+
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_SetMsgHighwater()");
287+
288+
if (ssh) {
289+
ssh->msgHighwaterMark = highwater;
290+
291+
return WS_SUCCESS;
292+
}
293+
294+
return WS_BAD_ARGUMENT;
295+
}
296+
297+
298+
word32 wolfSSH_GetMsgHighwater(WOLFSSH* ssh)
299+
{
300+
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_GetMsgHighwater()");
301+
302+
if (ssh)
303+
return ssh->msgHighwaterMark;
304+
305+
return 0;
306+
}
307+
308+
270309
void wolfSSH_SetHighwaterCb(WOLFSSH_CTX* ctx, word32 highwater,
271310
WS_CallbackHighwater cb)
272311
{

wolfssh/internal.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,12 @@ enum NameIdType {
443443
#ifndef DEFAULT_HIGHWATER_MARK
444444
#define DEFAULT_HIGHWATER_MARK ((1024 * 1024 * 1024) - (32 * 1024))
445445
#endif
446+
#ifndef WOLFSSH_DEFAULT_MSG_HIGHWATER_MARK
447+
/* RFC 4344 Sec 3.1: bound packets per key epoch to limit cipher/IV
448+
* exhaustion under a single key (not the absolute SSH sequence number,
449+
* which is not reset by rekey); default to 2^31 packets per key. */
450+
#define WOLFSSH_DEFAULT_MSG_HIGHWATER_MARK (1U << 31)
451+
#endif
446452
#ifndef DEFAULT_WINDOW_SZ
447453
#define DEFAULT_WINDOW_SZ (128 * 1024)
448454
#endif
@@ -597,6 +603,7 @@ struct WOLFSSH_CTX {
597603
byte publicKeyAlgo[WOLFSSH_MAX_PUB_KEY_ALGO];
598604
word32 publicKeyAlgoCount;
599605
word32 highwaterMark;
606+
word32 msgHighwaterMark;
600607
const char* banner;
601608
const char* sshProtoIdStr;
602609
const char* algoListKex;
@@ -749,8 +756,12 @@ struct WOLFSSH {
749756
int wflags; /* optional write flags */
750757
word32 txCount;
751758
word32 rxCount;
759+
word32 txMsgCount; /* Packets sent under current keys */
760+
word32 rxMsgCount; /* Packets received under current keys */
752761
word32 highwaterMark;
762+
word32 msgHighwaterMark; /* Per-key packet limit (RFC 4344 Sec 3.1) */
753763
byte highwaterFlag; /* Set when highwater CB called */
764+
byte msgHighwaterFlag; /* Set when msg-count highwater CB called */
754765
void* highwaterCtx; /* Highwater CB context */
755766
void* globalReqCtx; /* Global Request CB context */
756767
void* reqSuccessCtx; /* Global Request Success CB context */

wolfssh/ssh.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,19 @@ WOLFSSH_API int wolfSSH_SetFilesystemHandle(WOLFSSH*, void*);
7878
WOLFSSH_API void* wolfSSH_GetFilesystemHandle(WOLFSSH*);
7979

8080
/* data high water mark functions */
81-
WOLFSSH_API int wolfSSH_SetHighwater(WOLFSSH*, word32);
82-
WOLFSSH_API word32 wolfSSH_GetHighwater(WOLFSSH*);
83-
84-
typedef int (*WS_CallbackHighwater)(byte, void*);
85-
WOLFSSH_API void wolfSSH_SetHighwaterCb(WOLFSSH_CTX*, word32,
86-
WS_CallbackHighwater);
87-
WOLFSSH_API void wolfSSH_SetHighwaterCtx(WOLFSSH*, void*);
88-
WOLFSSH_API void* wolfSSH_GetHighwaterCtx(WOLFSSH*);
81+
WOLFSSH_API int wolfSSH_SetHighwater(WOLFSSH* ssh, word32 highwater);
82+
WOLFSSH_API word32 wolfSSH_GetHighwater(WOLFSSH* ssh);
83+
84+
/* packet count high water mark functions (RFC 4344 Sec 3.1) */
85+
WOLFSSH_API int wolfSSH_CTX_SetMsgHighwater(WOLFSSH_CTX* ctx, word32 highwater);
86+
WOLFSSH_API int wolfSSH_SetMsgHighwater(WOLFSSH* ssh, word32 highwater);
87+
WOLFSSH_API word32 wolfSSH_GetMsgHighwater(WOLFSSH* ssh);
88+
89+
typedef int (*WS_CallbackHighwater)(byte side, void* ctx);
90+
WOLFSSH_API void wolfSSH_SetHighwaterCb(WOLFSSH_CTX* ctx,
91+
word32 highwater, WS_CallbackHighwater cb);
92+
WOLFSSH_API void wolfSSH_SetHighwaterCtx(WOLFSSH* ssh, void* ctx);
93+
WOLFSSH_API void* wolfSSH_GetHighwaterCtx(WOLFSSH* ssh);
8994

9095
WOLFSSH_API int wolfSSH_ReadKey_buffer_ex(const byte* in, word32 inSz, int format,
9196
byte** out, word32* outSz, const byte** outType, word32* outTypeSz,

0 commit comments

Comments
 (0)