View Issue Details

IDProjectCategoryView StatusLast Update
0005583SOGoBackend Generalpublic2022-08-20 01:05
Reporterabashurov Assigned To 
PrioritynormalSeveritymajorReproducibilityalways
Status newResolutionopen 
Product Version5.7.1 
Summary0005583: sym-aes-128-cbc userPasswordAlgorithm does not support passwords longer than 16 symbols
Description

AES-128-CBC password check limits the block size to 16 symbols: https://github.com/Alinto/sogo/blob/master/SoObjects/SOGo/NSData%2BCrypto.m#L637

AES128_CBC_encrypt_buffer, however, will emit more than 16 symbols in case input data exceeds the length of a block (16 symbols as well): https://github.com/Alinto/sogo/blob/master/SoObjects/SOGo/aes.c#L519

Steps To Reproduce
  1. Set up SQL-backed authentication as described in the documentation with the "sym-aes-128-cbc" encryption method. Excerpt from the configuration:
    SOGoUserSources = (
    {
      type = sql;
      id = plesk;
      viewURL = "mysql://sogo:sogopasswd@localhost:3306/psa/sogoMailSource";
      userPasswordAlgorithm = "sym-aes-128-cbc";
      prependPasswordScheme = NO;
      keyPath = "/etc/sogo/sw_private_key";
      canAuthenticate = YES;
      isAddressBook = NO;
    }
    );
  2. Insert the following data into the SQL server:
    CREATE TABLE sogoMailSource(`c_uid` VARCHAR(128) NOT NULL, `c_name` VARCHAR(128) NOT NULL, `c_password` VARCHAR(128), `c_cn` VARCHAR(128) NULL, `mail` VARCHAR(128) NOT NULL, PRIMARY KEY (`c_uid`));
    INSERT INTO sogoMailSource(c_uid, c_name, c_password, c_cn, mail) VALUES('test@a10-52-36-116.qa.plesk.tech', 'test@a10-52-36-116.qa.plesk.tech', '$AES-128-CBC$JTJadZKgoNNOa9yAGlPPQA==$vLPvhY2tcyNWaYtGiY26T5GFmuEg2/O5PJeIrPs4C5Q=', 'test@a10-52-36-116.qa.plesk.tech', 'test@a10-52-36-116.qa.plesk.tech');
  3. Use the following private key:
    echo 'KNsJZ4y5PTQTh0AB4As3kg==' | base64 -d > /etc/sogo/sw_private_key && chown sogo:root /etc/sogo/sw_private_key
  4. Attempt to log in as user 'test@a10-52-36-116.qa.plesk.tech' with password 'AWcxm8CyKpgjWJOPHPUoXg=='

Expected result: authentication success

Actual result: authentication failure

Additional Information

The minimal required patch for the issue is attached.

Please also note that AES128_CBC_encrypt_buffer does not restrict the length of the incoming data, therefore providing a password input longer than 256 symbols will cause buffer overflow, as provided buffer is limited: https://github.com/Alinto/sogo/blob/master/SoObjects/SOGo/NSData%2BCrypto.m#L613

Tagspassword

Activities

abashurov

abashurov

2022-08-20 01:05

reporter  

diff (2,660 bytes)   
diff --git a/SoObjects/SOGo/NSData+Crypto.m b/SoObjects/SOGo/NSData+Crypto.m
index 6a2f241d1..8322c502e 100644
--- a/SoObjects/SOGo/NSData+Crypto.m
+++ b/SoObjects/SOGo/NSData+Crypto.m
@@ -611,7 +611,7 @@ static const char salt_chars[] =
   NSString *s;
 
   char ciphertext[256], *iv_s, *key_s, *pass;
-  unsigned int len;
+  unsigned int len, enc_len;
 
   len = ceil((double)[self length]/16) * 16;
 
@@ -632,9 +632,9 @@ static const char salt_chars[] =
 
   pass = calloc(len, sizeof(char));
   strncpy(pass, [self bytes], [self length]);
-  AES128_CBC_encrypt_buffer((uint8_t*)ciphertext, (uint8_t*)pass, (uint32_t)len, (const uint8_t*)key_s, (const uint8_t*)iv_s);
+  enc_len = AES128_CBC_encrypt_buffer((uint8_t*)ciphertext, (uint8_t*)pass, (uint32_t)len, (const uint8_t*)key_s, (const uint8_t*)iv_s);
 
-  cipherdata = [NSData dataWithBytes: ciphertext  length: 16];
+  cipherdata = [NSData dataWithBytes: ciphertext  length: enc_len];
   s = [[NSString alloc] initWithData: [cipherdata dataByEncodingBase64WithLineLength: 1024]
                             encoding: NSASCIIStringEncoding];
 
diff --git a/SoObjects/SOGo/aes.c b/SoObjects/SOGo/aes.c
index de104ed9c..c054969ac 100644
--- a/SoObjects/SOGo/aes.c
+++ b/SoObjects/SOGo/aes.c
@@ -496,7 +496,7 @@ static void XorWithIv(uint8_t* buf)
   }
 }
 
-void AES128_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
+size_t AES128_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
 {
   size_t i;
   uint8_t remainders = length % KEYLEN; /* Remaining bytes in the last non-full block */
@@ -534,6 +534,8 @@ void AES128_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length,
     state = (state_t*)output;
     Cipher();
   }
+
+  return i;
 }
 
 void AES128_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
diff --git a/SoObjects/SOGo/aes.h b/SoObjects/SOGo/aes.h
index b95cf7fb0..08b1cefed 100644
--- a/SoObjects/SOGo/aes.h
+++ b/SoObjects/SOGo/aes.h
@@ -30,7 +30,7 @@ void AES128_ECB_decrypt(uint8_t* input, const uint8_t* key, uint8_t *output);
 
 #if defined(CBC) && CBC
 
-void AES128_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);
+size_t AES128_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);
 void AES128_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);
 
 /* These variants encrypt and decrypt the data block in-place.
diff (2,660 bytes)   

Issue History

Date Modified Username Field Change
2022-08-20 01:05 abashurov New Issue
2022-08-20 01:05 abashurov Tag Attached: password
2022-08-20 01:05 abashurov File Added: diff