Browse Source

Bug 2019: Error when uploading file sized just below 32 kB boundary to FTP server over TLS 1.3

https://winscp.net/tracker/2019

Source commit: 20c418a5e796357ab6e842d95bf3614a21f1e4fc
Martin Prikryl 2 years ago
parent
commit
e5628b72f3

+ 16 - 2
source/core/FtpFileSystem.cpp

@@ -19,6 +19,7 @@
 #include <StrUtils.hpp>
 #include <DateUtils.hpp>
 #include <openssl/x509_vfy.h>
+#include <limits>
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
@@ -2823,8 +2824,21 @@ int __fastcall TFTPFileSystem::GetOptionVal(int OptionID) const
       break;
 
     case OPTION_MPEXT_WORK_FROM_CWD:
-       Result = (FWorkFromCwd == asOn);
-       break;
+      Result = (FWorkFromCwd == asOn);
+      break;
+
+    case OPTION_MPEXT_TRANSFER_SIZE:
+      {
+        __int64 TransferSize = 0;
+        if ((FTerminal->OperationProgress != NULL) &&
+            (FTerminal->OperationProgress->Operation == foCopy) &&
+            (FTerminal->OperationProgress->Side == osLocal))
+        {
+          TransferSize = FTerminal->OperationProgress->TransferSize - FTerminal->OperationProgress->TransferredSize;
+        }
+        Result = static_cast<int>(static_cast<unsigned int>(TransferSize & std::numeric_limits<unsigned int>::max()));
+      }
+      break;
 
     default:
       DebugFail();

+ 28 - 1
source/filezilla/AsyncSslSocketLayer.cpp

@@ -797,7 +797,34 @@ int CAsyncSslSocketLayer::InitSSLConnection(bool clientMode,
 
   //Create bios
   m_sslbio = BIO_new(BIO_f_ssl());
-  BIO_new_bio_pair(&m_ibio, 32768, &m_nbio, 32768);
+  // WORKAROUND: Upload over TLS 1.3 fails for specific sizes in relation to OpenSSL buffer size.
+  // For 32768 buffer, the sizes are 32725-32746, 65471-65492, 98217-98238 (tested up to 1048576)
+  // Do not know how to fix that, so as a workaround, using buffer size that does not result in the problem.
+  unsigned long TransferSize = 0;
+  if (main != NULL)
+  {
+    TransferSize = static_cast<unsigned long>(GetSocketOptionVal(OPTION_MPEXT_TRANSFER_SIZE));
+  }
+  unsigned BufferKBs = 32;
+  unsigned long BufferSize;
+  do
+  {
+    BufferSize = BufferKBs * 1024;
+    int Remainder = TransferSize % BufferSize;
+    int BufferCount = (TransferSize / BufferSize) + (Remainder > 0 ? 1 : 0);
+    int ProblemHigh = BufferSize - (BufferCount * 22);
+    int ProblemLow = ProblemHigh - 21;
+    if ((ProblemLow <= Remainder) && (Remainder <= ProblemHigh))
+    {
+      BufferKBs++;
+    }
+    else
+    {
+      break;
+    }
+  }
+  while (true);
+  BIO_new_bio_pair(&m_ibio, BufferSize, &m_nbio, BufferSize);
 
   if (!m_sslbio || !m_nbio || !m_ibio)
   {

+ 1 - 0
source/filezilla/FileZillaOpt.h

@@ -53,5 +53,6 @@
 #define OPTION_MPEXT_COMPLETE_TLS_SHUTDOWN 1012
 #define OPTION_MPEXT_CERT_STORAGE 1013
 #define OPTION_MPEXT_WORK_FROM_CWD 1014
+#define OPTION_MPEXT_TRANSFER_SIZE 1015
 //---------------------------------------------------------------------------
 #endif // FileZillaOptH