Skip to content

Commit 226c39b

Browse files
Add independent ciper and MAC algorithms negotiation for each direction, And add regress test
1 parent 834e60f commit 226c39b

3 files changed

Lines changed: 1042 additions & 54 deletions

File tree

src/internal.c

Lines changed: 130 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -570,13 +570,11 @@ static HandshakeInfo* HandshakeInfoNew(void* heap)
570570
heap, DYNTYPE_HS);
571571
if (newHs != NULL) {
572572
WMEMSET(newHs, 0, sizeof(HandshakeInfo));
573-
newHs->expectMsgId = MSGID_NONE;
574-
newHs->kexId = ID_NONE;
575573
newHs->kexHashId = WC_HASH_TYPE_NONE;
576-
newHs->pubKeyId = ID_NONE;
577-
newHs->encryptId = ID_NONE;
578-
newHs->macId = ID_NONE;
579574
newHs->blockSz = MIN_BLOCK_SZ;
575+
newHs->peerBlockSz = MIN_BLOCK_SZ;
576+
/* peerEncryptId, peerMacId, peerAeadMode, peerMacSz: left at 0
577+
* (== ID_NONE / no-MAC) by the WMEMSET above. */
580578
newHs->eSz = (word32)sizeof(newHs->e);
581579
newHs->xSz = (word32)sizeof(newHs->x);
582580
#ifndef WOLFSSH_NO_DH_GEX_SHA256
@@ -2625,7 +2623,7 @@ static int GenerateKeys(WOLFSSH* ssh, byte hashId, byte doKeyPad)
26252623
Keys* sK = NULL;
26262624
int ret = WS_SUCCESS;
26272625

2628-
if (ssh == NULL)
2626+
if (ssh == NULL || ssh->handshake == NULL)
26292627
ret = WS_BAD_ARGUMENT;
26302628
else {
26312629
if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) {
@@ -2658,19 +2656,17 @@ static int GenerateKeys(WOLFSSH* ssh, byte hashId, byte doKeyPad)
26582656
sK->encKey, sK->encKeySz,
26592657
ssh->k, ssh->kSz, ssh->h, ssh->hSz,
26602658
ssh->sessionId, ssh->sessionIdSz, doKeyPad);
2661-
if (ret == WS_SUCCESS) {
2662-
if (!ssh->handshake->aeadMode) {
2663-
ret = GenerateKey(hashId, 'E',
2664-
cK->macKey, cK->macKeySz,
2665-
ssh->k, ssh->kSz, ssh->h, ssh->hSz,
2666-
ssh->sessionId, ssh->sessionIdSz, doKeyPad);
2667-
if (ret == WS_SUCCESS) {
2668-
ret = GenerateKey(hashId, 'F',
2669-
sK->macKey, sK->macKeySz,
2670-
ssh->k, ssh->kSz, ssh->h, ssh->hSz,
2671-
ssh->sessionId, ssh->sessionIdSz, doKeyPad);
2672-
}
2673-
}
2659+
if (ret == WS_SUCCESS && cK->macKeySz > 0) {
2660+
ret = GenerateKey(hashId, 'E',
2661+
cK->macKey, cK->macKeySz,
2662+
ssh->k, ssh->kSz, ssh->h, ssh->hSz,
2663+
ssh->sessionId, ssh->sessionIdSz, doKeyPad);
2664+
}
2665+
if (ret == WS_SUCCESS && sK->macKeySz > 0) {
2666+
ret = GenerateKey(hashId, 'F',
2667+
sK->macKey, sK->macKeySz,
2668+
ssh->k, ssh->kSz, ssh->h, ssh->hSz,
2669+
ssh->sessionId, ssh->sessionIdSz, doKeyPad);
26742670
}
26752671

26762672
#ifdef SHOW_SECRETS
@@ -4258,6 +4254,18 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
42584254
word32 cannedAlgoNamesSz;
42594255
word32 skipSz = 0;
42604256
word32 begin;
4257+
/* handshake->keys/encryptId/... always represent the LOCAL endpoint's
4258+
* outgoing direction; peer* counterparts represent the peer's outgoing
4259+
* (= our incoming) direction. Server: local=S2C, peer=C2S.
4260+
* Client: local=C2S, peer=S2C. These aliases let the four enc/MAC
4261+
* parse sections store results without inline side checks, and keep the
4262+
* fields consistent with what GenerateKeys/SendNewKeys/DoNewKeys expect. */
4263+
byte *c2sEncryptId = NULL, *c2sAeadMode = NULL, *c2sBlockSz = NULL,
4264+
*c2sMacId = NULL, *c2sMacSz = NULL;
4265+
Keys *c2sKeys = NULL;
4266+
byte *s2cEncryptId = NULL, *s2cAeadMode = NULL, *s2cBlockSz = NULL,
4267+
*s2cMacId = NULL, *s2cMacSz = NULL;
4268+
Keys *s2cKeys = NULL;
42614269

42624270
WLOG(WS_LOG_DEBUG, "Entering DoKexInit()");
42634271

@@ -4300,6 +4308,35 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
43004308
begin = *idx;
43014309
side = ssh->ctx->side;
43024310

4311+
if (side == WOLFSSH_ENDPOINT_SERVER) {
4312+
c2sEncryptId = &ssh->handshake->peerEncryptId;
4313+
c2sAeadMode = &ssh->handshake->peerAeadMode;
4314+
c2sBlockSz = &ssh->handshake->peerBlockSz;
4315+
c2sMacId = &ssh->handshake->peerMacId;
4316+
c2sMacSz = &ssh->handshake->peerMacSz;
4317+
c2sKeys = &ssh->handshake->peerKeys;
4318+
s2cEncryptId = &ssh->handshake->encryptId;
4319+
s2cAeadMode = &ssh->handshake->aeadMode;
4320+
s2cBlockSz = &ssh->handshake->blockSz;
4321+
s2cMacId = &ssh->handshake->macId;
4322+
s2cMacSz = &ssh->handshake->macSz;
4323+
s2cKeys = &ssh->handshake->keys;
4324+
}
4325+
else {
4326+
c2sEncryptId = &ssh->handshake->encryptId;
4327+
c2sAeadMode = &ssh->handshake->aeadMode;
4328+
c2sBlockSz = &ssh->handshake->blockSz;
4329+
c2sMacId = &ssh->handshake->macId;
4330+
c2sMacSz = &ssh->handshake->macSz;
4331+
c2sKeys = &ssh->handshake->keys;
4332+
s2cEncryptId = &ssh->handshake->peerEncryptId;
4333+
s2cAeadMode = &ssh->handshake->peerAeadMode;
4334+
s2cBlockSz = &ssh->handshake->peerBlockSz;
4335+
s2cMacId = &ssh->handshake->peerMacId;
4336+
s2cMacSz = &ssh->handshake->peerMacSz;
4337+
s2cKeys = &ssh->handshake->peerKeys;
4338+
}
4339+
43034340
/* Check that the cookie exists inside the message */
43044341
if (begin + COOKIE_SZ > len) {
43054342
/* error, out of bounds */
@@ -4399,6 +4436,24 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
43994436
ret = WS_MATCH_ENC_ALGO_E;
44004437
}
44014438
}
4439+
if (ret == WS_SUCCESS) {
4440+
*c2sEncryptId = algoId;
4441+
*c2sAeadMode = AeadModeForId(algoId);
4442+
*c2sBlockSz = BlockSzForId(algoId);
4443+
c2sKeys->encKeySz = KeySzForId(algoId);
4444+
if (!*c2sAeadMode) {
4445+
c2sKeys->ivSz = *c2sBlockSz;
4446+
}
4447+
else {
4448+
/* Reaching here requires an AEAD cipher ID, which requires
4449+
* WOLFSSH_NO_AES_GCM to be unset, hence WOLFSSH_NO_AEAD unset
4450+
* (see internal.h). */
4451+
c2sKeys->ivSz = AEAD_NONCE_SZ;
4452+
*c2sMacSz = *c2sBlockSz;
4453+
*c2sMacId = ID_NONE;
4454+
c2sKeys->macKeySz = 0;
4455+
}
4456+
}
44024457

44034458
/* Enc Algorithms - Server to Client */
44044459
if (ret == WS_SUCCESS) {
@@ -4407,31 +4462,32 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
44074462
ret = GetNameList(list, &listSz, buf, len, &begin);
44084463
}
44094464
if (ret == WS_SUCCESS) {
4410-
algoId = MatchIdLists(side, list, listSz, &algoId, 1);
4465+
cannedAlgoNamesSz = AlgoListSz(ssh->algoListCipher);
4466+
cannedListSz = (word32)sizeof(cannedList);
4467+
ret = GetNameListRaw(cannedList, &cannedListSz,
4468+
(const byte*)ssh->algoListCipher, cannedAlgoNamesSz);
4469+
}
4470+
if (ret == WS_SUCCESS) {
4471+
algoId = MatchIdLists(side, list, listSz, cannedList, cannedListSz);
44114472
if (algoId == ID_UNKNOWN) {
44124473
WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo S2C");
44134474
ret = WS_MATCH_ENC_ALGO_E;
44144475
}
44154476
}
44164477
if (ret == WS_SUCCESS) {
4417-
ssh->handshake->encryptId = algoId;
4418-
ssh->handshake->aeadMode = AeadModeForId(algoId);
4419-
ssh->handshake->blockSz = BlockSzForId(algoId);
4420-
ssh->handshake->keys.encKeySz =
4421-
ssh->handshake->peerKeys.encKeySz =
4422-
KeySzForId(algoId);
4423-
if (!ssh->handshake->aeadMode) {
4424-
ssh->handshake->keys.ivSz =
4425-
ssh->handshake->peerKeys.ivSz =
4426-
ssh->handshake->blockSz;
4478+
*s2cEncryptId = algoId;
4479+
*s2cAeadMode = AeadModeForId(algoId);
4480+
*s2cBlockSz = BlockSzForId(algoId);
4481+
s2cKeys->encKeySz = KeySzForId(algoId);
4482+
if (!*s2cAeadMode) {
4483+
s2cKeys->ivSz = *s2cBlockSz;
44274484
}
44284485
else {
4429-
#ifndef WOLFSSH_NO_AEAD
4430-
ssh->handshake->keys.ivSz =
4431-
ssh->handshake->peerKeys.ivSz =
4432-
AEAD_NONCE_SZ;
4433-
ssh->handshake->macSz = ssh->handshake->blockSz;
4434-
#endif
4486+
/* Same invariant as C2S: AEAD cipher ID implies !WOLFSSH_NO_AEAD. */
4487+
s2cKeys->ivSz = AEAD_NONCE_SZ;
4488+
*s2cMacSz = *s2cBlockSz;
4489+
*s2cMacId = ID_NONE;
4490+
s2cKeys->macKeySz = 0;
44354491
}
44364492
}
44374493

@@ -4441,7 +4497,7 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
44414497
listSz = (word32)sizeof(list);
44424498
ret = GetNameList(list, &listSz, buf, len, &begin);
44434499
}
4444-
if (ret == WS_SUCCESS && !ssh->handshake->aeadMode) {
4500+
if (ret == WS_SUCCESS && !*c2sAeadMode) {
44454501
cannedAlgoNamesSz = AlgoListSz(ssh->algoListMac);
44464502
cannedListSz = (word32)sizeof(cannedList);
44474503
ret = GetNameListRaw(cannedList, &cannedListSz,
@@ -4453,6 +4509,11 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
44534509
WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo C2S");
44544510
ret = WS_MATCH_MAC_ALGO_E;
44554511
}
4512+
else {
4513+
*c2sMacId = algoId;
4514+
*c2sMacSz = MacSzForId(algoId);
4515+
c2sKeys->macKeySz = KeySzForId(algoId);
4516+
}
44564517
}
44574518
}
44584519

@@ -4462,18 +4523,22 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
44624523
listSz = (word32)sizeof(list);
44634524
ret = GetNameList(list, &listSz, buf, len, &begin);
44644525
}
4465-
if (ret == WS_SUCCESS && !ssh->handshake->aeadMode) {
4466-
algoId = MatchIdLists(side, list, listSz, &algoId, 1);
4467-
if (algoId == ID_UNKNOWN) {
4468-
WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo S2C");
4469-
ret = WS_MATCH_MAC_ALGO_E;
4470-
}
4471-
else {
4472-
ssh->handshake->macId = algoId;
4473-
ssh->handshake->macSz = MacSzForId(algoId);
4474-
ssh->handshake->keys.macKeySz =
4475-
ssh->handshake->peerKeys.macKeySz =
4476-
KeySzForId(algoId);
4526+
if (ret == WS_SUCCESS && !*s2cAeadMode) {
4527+
cannedAlgoNamesSz = AlgoListSz(ssh->algoListMac);
4528+
cannedListSz = (word32)sizeof(cannedList);
4529+
ret = GetNameListRaw(cannedList, &cannedListSz,
4530+
(const byte*)ssh->algoListMac, cannedAlgoNamesSz);
4531+
if (ret == WS_SUCCESS) {
4532+
algoId = MatchIdLists(side, list, listSz, cannedList, cannedListSz);
4533+
if (algoId == ID_UNKNOWN) {
4534+
WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo S2C");
4535+
ret = WS_MATCH_MAC_ALGO_E;
4536+
}
4537+
else {
4538+
*s2cMacId = algoId;
4539+
*s2cMacSz = MacSzForId(algoId);
4540+
s2cKeys->macKeySz = KeySzForId(algoId);
4541+
}
44774542
}
44784543
}
44794544

@@ -6226,11 +6291,11 @@ static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
62266291
}
62276292

62286293
if (ret == WS_SUCCESS) {
6229-
ssh->peerEncryptId = ssh->handshake->encryptId;
6230-
ssh->peerMacId = ssh->handshake->macId;
6231-
ssh->peerBlockSz = ssh->handshake->blockSz;
6232-
ssh->peerMacSz = ssh->handshake->macSz;
6233-
ssh->peerAeadMode = ssh->handshake->aeadMode;
6294+
ssh->peerEncryptId = ssh->handshake->peerEncryptId;
6295+
ssh->peerMacId = ssh->handshake->peerMacId;
6296+
ssh->peerBlockSz = ssh->handshake->peerBlockSz;
6297+
ssh->peerMacSz = ssh->handshake->peerMacSz;
6298+
ssh->peerAeadMode = ssh->handshake->peerAeadMode;
62346299
WMEMCPY(&ssh->peerKeys, &ssh->handshake->peerKeys, sizeof(Keys));
62356300

62366301
switch (ssh->peerEncryptId) {
@@ -17960,6 +18025,17 @@ int wolfSSH_TestDoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
1796018025
return DoKexInit(ssh, buf, len, idx);
1796118026
}
1796218027

18028+
int wolfSSH_TestDoNewKeys(WOLFSSH* ssh)
18029+
{
18030+
/* DoNewKeys ignores buf/len/idx (marked WOLFSSH_UNUSED internally). */
18031+
return DoNewKeys(ssh, NULL, 0, NULL);
18032+
}
18033+
18034+
int wolfSSH_TestGenerateKeys(WOLFSSH* ssh, byte hashId)
18035+
{
18036+
return GenerateKeys(ssh, (enum wc_HashType)hashId, 1);
18037+
}
18038+
1796318039
int wolfSSH_TestDoKexDhInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
1796418040
{
1796518041
return DoKexDhInit(ssh, buf, len, idx);

0 commit comments

Comments
 (0)