Obtaining SSL certificate info from SSL object - BUG?
nagle at animats.com
Fri Oct 27 08:03:34 CEST 2006
Michael Ströder wrote:
> John Nagle wrote:
>> The Python SSL object offers two methods from obtaining
>>the info from an SSL certificate, "server()" and "issuer()".
>>The actual values in the certificate are a series of name/value
>>pairs in ASN.1 binary format. But what "server()" and "issuer()"
>>return are strings, with the pairs separated by "/". The
>>documentation at "http://docs.python.org/lib/ssl-objects.html"
>>says "Returns a string containing the ASN.1 distinguished name
>>identifying the server's certificate. (See below for an example showing
>>what distinguished names look like.)" There is, however, no "below".
>>What you actually get back looks like this, which is Google's certificate:
>>"/C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com"
>>So, no problem; just split on "/", right?
>>Unfortunately, "/" is a legal character in certificate values.
> You hit a really serious problem: There's no completely well-defined
> string representation format for distinguished names used in X.509
> certificates. The format above is what OpenSSL used in the beginning.
> Yuck! IMO this is also a security problem in some cases.
> The best thing would be to stick to RFC 4514 (formerly RFC 2253:
> Lightweight Directory Access Protocol (LDAP): String Representation of
> Distinguished Names). It defines a UTF-8-based string representation.
> Guess the second is what Python SSL object also should return. No idea
> whether this is available at OpenSSL's API level.
That's exactly what I suggested in my Python bug report update.
OpenSSL has all the right functions. Almost.
OpenSSL has "X509_NAME_oneline()" which is deprecated, which Python
is using, and which uses "/" as a delimiter without escaping "/" in
OpenSSL also has "X509_NAME_print_ex", which does the right
thing - outputs a UTF8 string in RFC 2253 format, with all the
right escapes and Unicode compatibility if you ask for Unicode
Unfortunately, "X509_NAME_print_ex" is set up to output to
an I/O port, not a string. There's no comparable function in
OpenSSL to edit that info to a string.
All the right machinery to do the job is in
but they ran into a classic C problem. They have code designed
to output to a stream of infinite length, and don't have a way
to get the target length down to the copy function. Take look at
"send_mem_chars" in that file, which is turned off. If it were
used, it would have buffer overflow potential. This could be
fixed, but it's a pain. It's local to that file, though;
someone who owns that code could fix it in an hour.
X509_NAME_oneline(), the deprecated function, is in a
completely separate file and doesn't handle the hard cases at all.
The same problem was reported in Apache mod_ssl back in 2004. See
And it had to be fixed in OpenCA. See
Also, there may be an exploitable bug in MySQL that depends on this. See
Get the OpenSSL people to fix their API, and the Python fix will
be a one-line change.
More information about the Python-list