From: exarkun on
On 04:51 pm, nagle(a)animats.com wrote:
> I'm converting some code from M2Crypto to the new "ssl" module, and
>I've found what looks like a security hole. The "ssl" module will
>validate the certificate chain, but it doesn't check that the
>certificate
>is valid for the domain.
>
> Here's the basic code:
>
> sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
> sock = ssl.wrap_socket(sk, ca_certs=certfile,
> cert_reqs=ssl.CERT_REQUIRED)
> sock.connect((domain,443))
> cert = sock.getpeercert()
> print('SSL cert for "%s":' % (domain,))
> for fieldname in cert :
> print(' %s = %s' % (fieldname, cert[fieldname]))
>
>Note that I'm sending a CA cert list and am specifying CERT_REQUIRED,
>so I should get a proper cert check.
>
>Now let's try a host that presents the wrong SSL cert. Try, in
>a browser,
>
> https://www.countrysidecabinetry.com
>
>You'll get an error. But the "ssl" module is happy with this cert:
>
>SSL cert for "www.countrysidecabinetry.com":
> notAfter = Dec 8 23:30:48 2010 GMT
> subject = ((('serialNumber',
>u'E5gMXaDjnqfFPID2KNdLTVNEE6PjtqOr'),), (('countryName', u'US'),),
>(('organizationName', u'customla
>serengravings.com'),), (('organizationalUnitName', u'GT57631608'),),
>(('organizationalUnitName', u'See www.rapidssl.com/resources/cp
>s (c)09'),), (('organizationalUnitName', u'Domain Control Validated -
>RapidSSL(R)'),), (('commonName', u'customlaserengravings.com')
>,))
>
>Note that the cert is for "customlaserengravings.com", but is being
>presented by "countrysidecabinetry.com". Fail.
>
>When I try this with M2Crypto, I get an SSL.Checker.WrongHost
>exception.
>That's what should happen.

It's a bit debatable. There probably should be a way to make this
happen, but it's far from clear that it's the only correct behavior.
And, as it turns out, there is a way to make it happen - call
getpeercert() and perform the check yourself. ;)

Here's some related discussion for an equivalent API in a different
module:

http://twistedmatrix.com/trac/ticket/4023

At the very least, the documentation for this should be very clear about
what is and is not being checked.

Jean-Paul
From: exarkun on
On 05:49 pm, nagle(a)animats.com wrote:
>exarkun(a)twistedmatrix.com wrote:
>>On 04:51 pm, nagle(a)animats.com wrote:
>>> I'm converting some code from M2Crypto to the new "ssl" module,
>>>and
>>>I've found what looks like a security hole. The "ssl" module will
>>>validate the certificate chain, but it doesn't check that the
>>>certificate
>>>is valid for the domain.
>...
>>It's a bit debatable. There probably should be a way to make this
>>happen, but it's far from clear that it's the only correct behavior.
>>And, as it turns out, there is a way to make it happen - call
>>getpeercert() and perform the check yourself. ;)
>
> "Checking it yourself" is non-trivial.

Yes. It'd be nice to having something in the stdlib which accepted a
hostname and a certificate and told you if they line up or not.
>The SSL module doesn't seem to let you read all the cert extensions,

Yes. That sucks. It was argued about on python-dev and ultimately the
people writing the code didn't want to expose everything. I don't
remember the exact argument for that position.
> It's very bad for the "ssl" module to both ignore this check and
>not have that mentioned prominently in the documentation.

I agree. As I said, I think the behavior should be well documented.

Jean-Paul