"ssl" module doesn't validate that domain of certificate is correct

geremy condra debatem1 at gmail.com
Mon Apr 19 20:59:39 CEST 2010


On Mon, Apr 19, 2010 at 1:49 PM, John Nagle <nagle at animats.com> wrote:
> exarkun at twistedmatrix.com wrote:
>>
>> On 04:51 pm, nagle at 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. The checking code has to
> understand DNS wildcards and additional domains in cert extensions.
> The SSL module doesn't seem to let you read all the cert extensions,
> (in particular, you don't get "certificatePolicies", so you can't
> tell if a cert is an "extended validation" cert) but it looks like
> you do get the subjectAltName fields present in the extensions, like this:
>
>  subjectAltName = (('DNS', 'www.chapinfurniture.com'),
>        ('DNS', 'chapinfurniture.com')))
>
>   So it's at least possible to check.  Almost.
>
>   (DNS wildcards look like this: "*.example.com".  It's also possible
> to have "*.*.example.com".  However, no DNS wildcard cert should cover
> more than one second-level domain (huge security hole if you allow that)
> and no extended validation cert should have a wildcard.)
>
>   There may also be issues with internationalized domain names.
>
>   It's very bad for the "ssl" module to both ignore this check and
> not have that mentioned prominently in the documentation.  This is
> a security-critical function.  Somewhere, there's a Python program that
> can be exploited due to this bug.
>
>   Here's a comparison of what M2Crypto and the SSL module return, for
> "verisign.com", which uses most cert features.
>
> Trying domain "www.verisign.com"
> Host: www.verisign.com Port: 443
>
> Info from "M2Crypto: module:
>
> Cipher = DHE-RSA-AES256-SHA
>   Subject info: [('CN', 'verisign.com'),
>        ('OU', 'production Security Services  '),
>        ('O', 'VeriSign, Inc.'),
>        ('streetAddress', '487 East Middlefield Road'),
>        ('L', 'Mountain View'),
>        ('ST', 'California'),
>        ('postalCode', '94043'),
>        ('C', 'US'),
>        ('serialNumber', '2497886'),
>        ('2.5.4.15', 'V1.0, Clause 5.(b)'),
>        ('jurisdictionOfIncorporationStateOrProvinceName', 'Delaware'),
>        ('jurisdictionOfIncorporationCountryName', 'US')]
>
>  Certificate has 10 extensions.
> Extension #0: subjectAltName = DNS:verisign.com, DNS:www.verisign.com,
> DNS:verisign.mobi, DNS:www.verisign.mobi, DNS:verisign.eu, DN
> S:www.verisign.eu
> Extension #1: basicConstraints = CA:FALSE
> Extension #2: subjectKeyIdentifier =
> 0F:75:C5:F7:06:11:CE:74:FC:5F:DA:B6:2A:53:CE:39:1C:D6:7D:19
> Extension #3: keyUsage = Digital Signature, Key Encipherment
> Extension #4: crlDistributionPoints =
> URI:http://EVIntl-crl.verisign.com/EVIntl2006.crl
>
> Extension #5: certificatePolicies = Policy: 2.16.840.1.113733.1.7.23.6
>  CPS: https://www.verisign.com/rpa
>
> Extension #6: extendedKeyUsage = TLS Web Server Authentication, TLS Web
> Client Authentication, Netscape Server Gated Crypto
> Extension #7: authorityKeyIdentifier =
> keyid:4E:43:C8:1D:76:EF:37:53:7A:4F:F2:58:6F:94:F3:38:E2:D5:BD:DF
>
> Extension #8: authorityInfoAccess = OCSP -
> URI:http://EVIntl-ocsp.verisign.com
> CA Issuers - URI:http://EVIntl-aia.verisign.com/EVIntl2006.cer
>
> Extension #9: UNDEF = None
>
> Info from "ssl" module:
>
> SSL cert for "www.verisign.com":
>    notAfter = Apr  2 23:59:59 2012 GMT
>    subject = ((('1.3.6.1.4.1.311.60.2.1.3', u'US'),),
>                (('1.3.6.1.4.1.311.60.2.1.2', u'Delaware'),),
>                (('2.5.4.15', u'V1.0, Clause 5.(b)'),),
>                (('serialNumber', u'2497886'),),
>                (('countryName', u'US'),),
>                (('postalCode', u'94043'),),
>                (('stateOrProvinceName', u'California'),),
>                (('localityName', u'Mountain View'),),
>                (('streetAddress', u'487 East Middlefield Road'),),
>                (('organizationName', u'VeriSign, Inc.'),),
>                (('organizationalUnitName', u'production Security Services
>  '),),
>                (('commonName', u'verisign.com'),))
>
>
>                                John Nagle
> --
> http://mail.python.org/mailman/listinfo/python-list
>

I talked about this in my pycon lighting talk- it's actually been
known for some time, and in fact there's some comments in
Zope core that mention this problem being a motivation for
rewriting SSL support from scratch. IIRC (I seem to recall
this, but I seem to have lost my test harness for it) it also
impacts higher level libraries like urllib, but I would verify that
before taking it as gospel. Several of the other members of
python-crypto would know more about it than I.

As a side note, it also impacts IronPython.

Geremy Condra



More information about the Python-list mailing list