@@ -650,6 +650,22 @@ static int HashUpdate(wc_HashAlg* hash, enum wc_HashType type,
650650}
651651
652652
653+ /* Hash an mpint's length and optional 0 pad byte as one update of
654+ * LENGTH_SZ + pad bytes. For K the pad is secret: this avoids a branch on
655+ * it and a zero-length update, which some hash ports reject. The hashed
656+ * length still depends on the pad. */
657+ static INLINE int HashMpintHeader(wc_HashAlg* hash, enum wc_HashType type,
658+ word32 sz, byte pad)
659+ {
660+ byte hdr[LENGTH_SZ + 1];
661+
662+ pad &= 1;
663+ c32toa(sz + pad, hdr);
664+ hdr[LENGTH_SZ] = 0;
665+ return HashUpdate(hash, type, hdr, LENGTH_SZ + pad);
666+ }
667+
668+
653669/* returns WS_SUCCESS on success */
654670static INLINE int HighwaterCheck(WOLFSSH* ssh, byte side)
655671{
@@ -3535,8 +3551,6 @@ int GenerateKey(byte hashId, byte keyId,
35353551 wc_HashAlg hash;
35363552 enum wc_HashType enmhashId = (enum wc_HashType)hashId;
35373553 byte kPad = 0;
3538- byte pad = 0;
3539- byte kSzFlat[LENGTH_SZ];
35403554 int digestSz;
35413555 int ret;
35423556
@@ -3559,17 +3573,14 @@ int GenerateKey(byte hashId, byte keyId,
35593573 /* Data can be define as string and mpint. (see Section 5 of RFC4251).
35603574 * This padding is required in the case of an mpint, but not in the case of
35613575 * a string. */
3562- if (doKeyPad && (k[0] & 0x80)) kPad = 1;
3563- c32toa(kSz + kPad, kSzFlat);
3576+ kPad = (byte)((doKeyPad != 0) & (k[0] >> 7));
35643577
35653578 blocks = keySz / digestSz;
35663579 remainder = keySz % digestSz;
35673580
35683581 ret = wc_HashInit(&hash, enmhashId);
35693582 if (ret == WS_SUCCESS)
3570- ret = HashUpdate(&hash, enmhashId, kSzFlat, LENGTH_SZ);
3571- if (ret == WS_SUCCESS && kPad)
3572- ret = HashUpdate(&hash, enmhashId, &pad, 1);
3583+ ret = HashMpintHeader(&hash, enmhashId, kSz, kPad);
35733584 if (ret == WS_SUCCESS)
35743585 ret = HashUpdate(&hash, enmhashId, k, kSz);
35753586 if (ret == WS_SUCCESS)
@@ -3599,10 +3610,7 @@ int GenerateKey(byte hashId, byte keyId,
35993610 curBlock++) {
36003611 ret = wc_HashInit(&hash, enmhashId);
36013612 if (ret != WS_SUCCESS) break;
3602- ret = HashUpdate(&hash, enmhashId, kSzFlat, LENGTH_SZ);
3603- if (ret != WS_SUCCESS) break;
3604- if (kPad)
3605- ret = HashUpdate(&hash, enmhashId, &pad, 1);
3613+ ret = HashMpintHeader(&hash, enmhashId, kSz, kPad);
36063614 if (ret != WS_SUCCESS) break;
36073615 ret = HashUpdate(&hash, enmhashId, k, kSz);
36083616 if (ret != WS_SUCCESS) break;
@@ -3620,9 +3628,7 @@ int GenerateKey(byte hashId, byte keyId,
36203628 if (ret == WS_SUCCESS)
36213629 ret = wc_HashInit(&hash, enmhashId);
36223630 if (ret == WS_SUCCESS)
3623- ret = HashUpdate(&hash, enmhashId, kSzFlat, LENGTH_SZ);
3624- if (ret == WS_SUCCESS && kPad)
3625- ret = HashUpdate(&hash, enmhashId, &pad, 1);
3631+ ret = HashMpintHeader(&hash, enmhashId, kSz, kPad);
36263632 if (ret == WS_SUCCESS)
36273633 ret = HashUpdate(&hash, enmhashId, k, kSz);
36283634 if (ret == WS_SUCCESS)
@@ -7058,36 +7064,33 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
70587064 */
70597065static int CreateMpint(byte* buf, word32* sz, byte* pad)
70607066{
7061- word32 i;
7067+ word32 i, top, back ;
70627068
70637069 if (buf == NULL || sz == NULL || pad == NULL) {
70647070 WLOG(WS_LOG_ERROR, "Internal argument error with CreateMpint");
70657071 return WS_BAD_ARGUMENT;
70667072 }
70677073
7068- if (*sz == 0)
7069- return WS_SUCCESS;
7070-
70717074 /* check for leading 0's */
70727075 for (i = 0; i < *sz; i++) {
70737076 if (buf[i] != 0x00)
70747077 break;
70757078 }
7076- /* all-zero buffer encodes as empty mpint per RFC 4251 */
7079+ /* empty or all-zero buffer encodes as empty mpint per RFC 4251 */
70777080 if (i == *sz) {
70787081 *pad = 0;
70797082 *sz = 0;
70807083 return WS_SUCCESS;
70817084 }
70827085
7083- *pad = (buf[i] & 0x80) ? 1 : 0;
7084-
7085- /* if padding would be needed and have leading 0's already then do not add
7086- * extra 0's */
7087- if (i > 0 && *pad == 1) {
7088- i = i - 1 ;
7089- *pad = 0 ;
7090- }
7086+ /* If padding is needed and there is a leading 0 already, keep one 0
7087+ * instead of adding a pad byte. No branch on the MSB, which is secret
7088+ * for K. The leading-zero count still shows in the loop above and the
7089+ * move below; the mpint length depends on it by definition. */
7090+ top = (word32)buf[i] >> 7;
7091+ back = top & (word32)(i > 0) ;
7092+ i -= back ;
7093+ *pad = (byte)(top ^ back);
70917094
70927095 /* if i is still greater than 0 then the buffer needs shifted to remove
70937096 * leading 0's */
@@ -8834,13 +8837,7 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
88348837 }
88358838
88368839 if (ret == 0) {
8837- c32toa(ssh->kSz + kPad, scratchLen);
8838- ret = HashUpdate(hash, hashId, scratchLen, LENGTH_SZ);
8839- }
8840-
8841- if ((ret == 0) && (kPad)) {
8842- scratchLen[0] = 0;
8843- ret = HashUpdate(hash, hashId, scratchLen, 1);
8840+ ret = HashMpintHeader(hash, hashId, ssh->kSz, kPad);
88448841 }
88458842
88468843 if (ret == 0) {
@@ -18558,6 +18555,7 @@ int SendKexDhReply(WOLFSSH* ssh)
1855818555 c32toa(fSz + fPad, scratchLen);
1855918556 ret = HashUpdate(hash, hashId, scratchLen, LENGTH_SZ);
1856018557 }
18558+ /* f is public, so branching on its pad is fine. */
1856118559 if ((ret == 0) && (fPad)) {
1856218560 scratchLen[0] = 0;
1856318561 ret = HashUpdate(hash, hashId, scratchLen, 1);
@@ -18571,12 +18569,7 @@ int SendKexDhReply(WOLFSSH* ssh)
1857118569 ret = CreateMpint(ssh->k, &ssh->kSz, &kPad);
1857218570 }
1857318571 if (ret == 0) {
18574- c32toa(ssh->kSz + kPad, scratchLen);
18575- ret = HashUpdate(hash, hashId, scratchLen, LENGTH_SZ);
18576- }
18577- if ((ret == 0) && (kPad)) {
18578- scratchLen[0] = 0;
18579- ret = HashUpdate(hash, hashId, scratchLen, 1);
18572+ ret = HashMpintHeader(hash, hashId, ssh->kSz, kPad);
1858018573 }
1858118574 if (ret == 0) {
1858218575 ret = HashUpdate(hash, hashId, ssh->k, ssh->kSz);
@@ -26051,6 +26044,11 @@ int wolfSSH_TestChannelPutData(WOLFSSH_CHANNEL* channel, byte* data,
2605126044 return ChannelPutData(channel, data, dataSz);
2605226045}
2605326046
26047+ int wolfSSH_TestCreateMpint(byte* buf, word32* sz, byte* pad)
26048+ {
26049+ return CreateMpint(buf, sz, pad);
26050+ }
26051+
2605426052int wolfSSH_TestBuildNameList(char* buf, word32 bufSz,
2605526053 const byte* src, word32 srcSz)
2605626054{
0 commit comments