The consequences of your SSL certificate getting compromised
Suppose that your web server's SSL certificate's private key is compromised and stolen by an attacker. Further suppose that you detect this and replace the compromised certificate with a new one. Now, here's a question: what damage can the attacker still do with their stolen certificate?
- they can impersonate your web server. In theory they can only do this
until their stolen certificate expires; in practice, I think that many
users ignore 'expired certificate' errors because they are relatively
(SSL certificate revocation would protect against this, if it worked.)
- they may be able to decrypt any past SSL conversations that they've already captured, depending on what cipher was used.
The attacker cannot decrypt future SSL conversations, because those will be protected by your new certificate even if the SSL conversation uses a cipher without forward secrecy.
If the attacker compromised a wildcard certificate they can imitate any of your web servers, regardless of what certificate the web server normally uses, but can only potentially decrypt past conversations from web servers that used the wildcard certificate. (Of course, if you went to the bother and expense of getting a wildcard certificate, you're probably going to use it on all of your web servers.)
I believe that the only relatively certain way of stopping an attacker's use of the stolen certificate is to remove the name from your DNS. Of course, this often presents certain difficulties.
(It is not safe to turn the compromised name into a website that just redirects people to the new name, because that means that users are still using the old name; the attacker could interpose their fake version and just not redirect to your new name.)
Using Python to find out what cipher a SSL server is using
I have a new-found interest in finding out what ciphers various SSL servers around here are using in some easy and convenient way. Doing this in Perl is easy (there's an example here), but I prefer Python. I'd normally use pyOpenSSL, my favorite Python OpenSSL module, but unfortunately it doesn't (currently) have an interface to the necessary 'get the connection's cipher' OpenSSL routine, and there's no visible substitute for it.
.get_cipher_list() method of
looks tempting, I discovered through some experimentation that it
doesn't return anything like the list of ciphers that are common between
the server and the client.)
However, all is not lost; it turns out that the commonly available M2Crypto module does have enough functionality to do this. In fact, it's pretty easy, and so here is sample code to do it (omitting error checking, as usual):
from M2Crypto import SSL
def printcipher(host, port): ctx = SSL.Context('tlsv1') s = SSL.Connection(ctx) # No, really, all I care is that you successfully # negotiated SSL, especially as some of your checks # are broken. s.postConnectionCheck = None s.connect((host, port)) # The space at the end is [sic] if s.get_state() == "SSLOK ": c = s.get_cipher() cp = c.name() print "Cipher %s, %d bits" % (cp, len(c)) if cp.startswith("DHE-") or cp.startswith("EDH-"): print "forward secrecy: yes" else: print "forward secrecy: probably not" s.close()
This code works for protocols that start SSL/TLS immediately on connection, such as https or imaps. Extension to protocols that have a plaintext conversation and then start TLS (such as ESTMP with STARTTLS) is left as an exercise for the sufficiently interested.
I believe but am not sure that there is no point in asking for anything
except TLS v1; the OpenSSL
ciphers(1) manpage suggests that SSLv3 and
TLSv1 have the same set of ciphers. (Presumably this is TLS v1.0.)
(Note that M2Crypto is pretty under-documented; reading the source is not so much recommended as required. Fortunately it comes with a large set of examples.)