Thanks exvito for your detailed response.
Re 2 & 3: You're right on the nail :-)  See my previous email to Jason.
Re 4: I can't use the high level Transport mechanism as I am using Twisted (most of the time) through another library layer (pymodbus).
Re 5: My server is still using Python's bloated ThreadingTCPServer model.
Re 6: Right!

Bottom line, I suggested a change of argument name, from "ssl.optionsForClientTLS(hostName, ..." to "ssl.optionsForClientTLS(commonName, ..."

Regards, Enoch.

On 10/26/2017 05:20 AM, ex vito wrote:
On 2017-10-25, at 21:07, Enoch W. <> wrote:


I am using a self-signed CA to issue server and client(s) certificates. 

My server is using the standard Python ssl module. 
One client, that is using twisted.internet.ssl, consistently fails to connect with: 
On the Server:    [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:661), 
On the Client:    [WARNING] [('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')]

This is my code:

path = getModule(__name__).filePath.sibling(u'data')

txt = path.child(u'ca.crt').getContent()
cacert = ssl.Certificate.loadPEM(txt)
root = ssl.trustRootFromCertificates([cacert])

txt = path.child(u'client.pem').getContent()
mycert = ssl.PrivateCertificate.loadPEM(txt)

ctx = ssl.optionsForClientTLS(hostName, trustRoot=root, clientCertificate=mycert)

reactor.connectSSL(hostName, portNumber, factory, ctx)

I am using the latest git trunk code.
With a regular ssl client I don't have an issue.

A known bug?
I would review a few things before suspecting a bug.

Your code is using client side certificates (nice, not often seen) so both server and client need to validate each other's certificates on connection establishment. It seems they are both failing, but we're only looking at your client code though.

Here are a few ideas:

1. Double check your certificates: Issuers, Subjects, Dates, SANs, etc.

2. Check that the hostName in optionsForClientTLS matches the name in the server certificate.

3. Use the latest Twisted release instead of trunk, if possible.
   Do the same for pyOpenSSL and other dependencies.

4. On the client side try using SSL4ClientEndpoint instead of connectSSL.
   I'm almost sure they behave differently regarding validation (could not quickly find
   docs on that, though: I've had your problem before and I think I addressed it this way).

   Instead of reactor.connectSSL(...) go for something like:

   ep = endpoints.SSL4ClientEndpoint(
   client = yield ep.connect(factory)

   For completeness, even though my client skeleton is mostly your client code with
   this diff, a quick test shows that my client also establishes the TLS connection
   if I do the reverse: replace SSL4ClientEndpoint with connectSSL in my code.

   This may not be the culprit, but I would try and see if anything changes.

5. On the server side I have the following Twisted code skeleton:

   dhFile = filepath.FilePath(...)
   dhParams = ssl.DiffieHellmanParameters.fromFile(dhFile)
   caCert = ssl.Certificate.loadPEM(...)
   privateCert = ssl.PrivateCertificate.loadPEM(...)
   cf = ssl.CertificateOptions(
   ep = endpoints.SSL4ServerEndpoint(
   f = protocol.Factory.forProtocol(...)

   Your code is obviously different, if based on the standard library's ssl module.
   If 1 to 4 don't produce results, this is a good candidate for needing some work.
   Can you share a minimal version of that? I'll be glad to take it for a spin.

6. Double check your certificates, again. Triple-check them if managed manually.

For completeness and reference:
- See as a starting point
  Twisted TLS, containing useful information and working examples.
- My working test environment runs Linux with OpenSSL 1.0.1t.


Twisted-Python mailing list