Skip to content

Commit

Permalink
Merge pull request #4 from libssh2/dfandrich/shellfish
Browse files Browse the repository at this point in the history
Fix AES-GCM decryption of block spanning frames
  • Loading branch information
palmin authored Feb 22, 2023
2 parents f1dcab2 + 4ac055f commit 8afa3fc
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,7 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
(void) algo;

assert(blocksize <= sizeof(buf));
assert(cryptlen >= 0);

/* First block */
if(IS_FIRST(firstlast)) {
Expand Down
21 changes: 17 additions & 4 deletions src/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
#include "transport.h"
#include "mac.h"

#ifndef MAX
#define MAX(x,y) ((x)>(y)?(x):(y))
#endif
#ifndef MIN
#define MIN(x,y) ((x)<(y)?(x):(y))
#endif
Expand Down Expand Up @@ -150,13 +153,14 @@ decrypt(LIBSSH2_SESSION * session, unsigned char *source,
int decryptlen = MIN(blocksize, len);
/* The first block is special (since it needs to be decoded to get the
length of the remainder of the block) and takes priority. When the
length finally gets to the last blocksize bytes, it's the end. */
length finally gets to the last blocksize bytes, and there's no
more data to come, it's the end. */
int lowerfirstlast = IS_FIRST(firstlast) ? FIRST_BLOCK :
((len <= blocksize) ? LAST_BLOCK : MIDDLE_BLOCK);
((len <= blocksize) ? firstlast : MIDDLE_BLOCK);
/* If the last block would be less than a whole blocksize, combine it
with the previous block to make it larger. This ensures that the
whole MAC is included in a single decrypt call. */
if(CRYPT_FLAG_L(session, PKTLEN_AAD) && !IS_FIRST(firstlast)
if(CRYPT_FLAG_L(session, PKTLEN_AAD) && IS_LAST(firstlast)
&& (len < blocksize*2)) {
decryptlen = len;
lowerfirstlast = LAST_BLOCK;
Expand Down Expand Up @@ -637,7 +641,8 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
amount to decrypt even more */
if((p->data_num + numbytes) >= (p->total_num - skip)) {
/* decrypt the entire rest of the package */
numdecrypt = (p->total_num - skip) - p->data_num;
numdecrypt = MAX(0,
(int)(p->total_num - skip) - (int)p->data_num);
firstlast = LAST_BLOCK;
}
else {
Expand All @@ -652,6 +657,13 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
after it */
numbytes = 0;
}
if(CRYPT_FLAG_R(session, INTEGRATED_MAC)) {
/* Make sure that we save enough bytes to make the last
* block large enough to hold the entire integrated MAC */
numdecrypt = MIN(numdecrypt, (int)
(p->total_num - skip - blocksize - p->data_num));
numbytes = 0;
}
firstlast = MIDDLE_BLOCK;
}

Expand All @@ -660,6 +672,7 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
/* unencrypted data should not be decrypted at all */
numdecrypt = 0;
}
assert(numdecrypt >= 0);

/* if there are bytes to decrypt, do that */
if(numdecrypt > 0) {
Expand Down

0 comments on commit 8afa3fc

Please sign in to comment.