1

What's the easiest way to connect to a SMTP server that supports STARTTLS and get its server SSL certificate? I know it can be done using openssl with something like this

openssl s_client -starttls smtp -crlf -connect 192.168.0.1:25

How can I do it from within Python and I don't want to call openssl and parse its output. I looked at M2Crypto which is an openssl wrapper, but as far as I can tell that doesn't support starttls. An example of how to do it with a Python library would be very much appreciated.

mozza
  • 965
  • 1
  • 9
  • 9
  • This is really hard. As of now, Python's native SSL will not let you get details of an invalid certificate. It will only return the certificate information for a valid certificate. :( You'll need to use 3rd party libraries like PyOpenSSL or M2Crypto. See a related post here: http://stackoverflow.com/questions/7689941/how-can-i-retrieve-the-ssl-certificate-information-for-a-connection-whether-its – SilentSteel Sep 04 '13 at 02:16

3 Answers3

1

This returns a certificate in binary format (DER-encoded):

import socket, ssl
s = socket.socket()
s.connect(("host", 25))
s.send("STARTTLS\n")
s.recv(1000)
ss = ssl.wrap_socket(s)
certificate_der = ss.getpeercert(True)

This is jus to give you an idea, error handling, etc. is required of course. If you want to decode the information from the certificate you either have to prodivde a certificate authorities bundle/directory for acceptable CAs (getpeercert() will return a meaningfull dict in this case), or use a more capable ssl library, M2Crypto for example.

abbot
  • 27,408
  • 6
  • 54
  • 57
0

You could try something like:

import ssl
cert = ssl.get_server_certificate(('imap.gmail.com',993))

to get server's certificate

barti_ddu
  • 10,179
  • 1
  • 45
  • 53
  • This is okay for a normal SSL connection like imap over SSL, https etc, but not one that needs to be kicked off using STARTTLS. – mozza Feb 24 '11 at 18:54
  • @mozza: ah, i see. Have you looked at openssl wrapper library at https://launchpad.net/pyopenssl ? And afais, you're more interested in root ca itself than just sending mail message via smtp, right? – barti_ddu Feb 24 '11 at 19:23
0

As I can't comment abbot answer, just remark that depending on the server config you may need to send an EHLO before STARTTLS:

import socket, ssl

hostname = 'test.com'
port = 25

context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
    sock.recv(1000)
    sock.send(b'EHLO\nSTARTTLS\n')
    sock.recv(1000)
    with context.wrap_socket(sock, server_hostname=hostname) as sslsock:
        der_cert = sslsock.getpeercert(True)
Suriem
  • 119
  • 2
  • 5