If I use stunnel.exe (from stunnel.org), with the following stunnel config file, then Chilkat Ftp2 works and can establish data connections for uploading/downloading files. Here's the stunnel config file:
[My-FTP] accept = 2021 connect = my.ftpserver.com:2021 CAfile = my-ftp-servers-cert.pem verify = 3  accept = 4000 connect = my.ftpserver.com:2000 CAfile = my-ftp-servers-cert.pem verify = 3  accept = 4001 connect = my.ftpserver.com:2001 CAfile = my-ftp-servers-cert.pem verify = 3  accept = 4002 connect = my.ftpserver.com:2002 CAfile = my-ftp-servers-cert.pem verify = 3
 accept = 4020 connect = my.ftpserver.com:2020 CAfile = my-ftp-servers-cert.pem verify = 3
My application uses Chilkat Ftp2 and connects to localhost:2021 (which is the stunnel.exe). From my application's point of view, it is communicating with an FTP server without SSL/TLS, and it operates in passive mode for establishing data connections. The stunnel.exe provides the bi-directional SSL/TLS connections to the actual FTP server.
There are a number of things to explain. This is a very strange and unusual situation.
So how can this possibly work with stunnel, but now with FileZilla, Chilkat, or any other robust and mature FTP client software?
To get the answer, we have to examine and understand exactly what is happening. Here's what's happening when a data connection (in passive mode) is established in this situation through stunnel:
It turns out that stunnel is really being used to "map" the passive port from one value to another. Port 4010 becomes 2010. Port 4003 becomes port 2003, etc. Stunnel is just being used to account for this highly unusual (and incorrect) behavior.
When the FTP server replies to a PASV command, it SHOULD be replying with the port at which it will be listening for the data connection. If it says "I'll be listening at port 4014", it cannot then listen at port 2014 and expect the FTP server to magically know this. This is why FileZilla, Chilkat, and all other perfectly good and mature FTP clients cannot handle this situation. It is because the server is not behaving properly. The "sane" FTP clients (FileZilla, Chilkat, etc.) are trying to connect to the port that was clearly indicated by the server. Sadly, the server is not actually listening at the port. It lied.
The solution is to fix the incorrect behavior of the server. Perhaps it isn't the FTP server itself, but perhaps it is a software or hardware (deep-inspection) firewall that is modifying the PASV reply. If so, this is crazy and I've never seen anything like it before. The only possible solution here is to fix the server side so that the server is actually listening on the port that it says it is..