Problems with WinSCP verifying SSL certificates

Lately I’ve been working on setting up a file server on an Amazon ec2 instance with ProFTPD so that I can upload files using FTPS/SFTP. I had some issues getting FTPS to work correctly despite using a Rapid SSL certificate from GeoTrust that I purchased. I attempted first with FileZilla, and then with WinSCP but both gave me the below error and had problems verifying my SSL certificate.

Unable to get local issuer certificate. The error occurred at a depth of 2 in the certificate chain.

For reference the TLS section of my /etc/proftpd.conf file is as follows.

  TLSEngine                     on
  TLSRequired                   off
  #TLSRSACertificateFile        /etc/ssl/certs/certificate.crt
  TLSRSACertificateKeyFile      /etc/ssl/certs/private.key
  #TLSCACertificateFile         /etc/ssl/certs/intermediate.ca
  TLSCipherSuite                ALL:!ADH:!DES
  TLSCertificateChainFile       /etc/ssl/certs/concatenation.crt
  TLSVerifyClient               off
  TLSLog                        /var/log/proftpd/tls.log

Originally I had specified TLSRSACertificateFile and TLSCACertificateFile as shown above but instead commented them out and replaced them with TLSCertificateChainFile. The file specified here is a concatenation of my issued certificate from GeoTrust followed by the Intermediate CA that was also provided. For further information on using mod_tls see here.

Back to the error, after some searching and messaging a ProFTPD developer it appeared that my issue was to do with this bug. I am running ProFTPD 1.3.3g as this is the latest version in the epel repository currently and I didn’t compile the latest from source. The version I am using is the one before the patch so it made sense to me that this could be the problem, however it was not.

By looking into the WinSCP code we can check exactly how it is verifying the SSL certificate:

filezilla/AsyncSslSocketLayer.cpp
		if (clientMode)
		{
			USES_CONVERSION;
			pSSL_CTX_set_verify(m_ssl_ctx, SSL_VERIFY_PEER, verify_callback);
			pSSL_CTX_load_verify_locations(m_ssl_ctx, T2CA(m_CertStorage), 0);
		}
filezilla/AsyncSslSocketLayer.cpp
BOOL CAsyncSslSocketLayer::SetCertStorage(CString file)

{
	m_CertStorage = file;
	return TRUE;
}

filezilla/FtpControlSocket.cpp
		m_pSslLayer = new CAsyncSslSocketLayer;
		AddLayer(m_pSslLayer);
		TCHAR buffer[1000];
		GetModuleFileName(NULL, buffer, 1000);
		CString filename = buffer;
		int pos = filename.ReverseFind(_MPT('\\'));
		if (pos != -1)
		{
			filename = filename.Left(pos + 1);
			filename += _T("cacert.pem");
			m_pSslLayer->SetCertStorage(filename);
		}
		else
			filename = _MPT("cacert.pem");

So WinSCP uses OpenSSL to verify certificates, the function pSSL_CTX_load_verify_locations specifies the location of trusted CA certificates. In this instance we can see that it uses a file called cacert.pem in the same location as the running module.

Basically WinSCP does not come with pre-trusted certificates, which is preferable for security reasons but a bit inconvenient as I couldn’t find this information documented. The only information I could find was this which implied that the certificates from the Windows store would be used, and I definitely had the GeoTrust root certificate there.

To fix this I added all the Firefox CAs from http://curl.haxx.se/ca/

Just download cacert.pem from the above link and place it into the same folder as winscp.exe, then when you try to connect to the server with FTPS that has your certificate you shouldn’t get any certificate warnings.

  1. I could solve the problem for WINSCP by running it with the /ini=WinSCP.ini option and it worked

Leave a Comment

NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>