From ffe576dc78cbdfb5f5e5625fa0a54ca1ce7b3bdc Mon Sep 17 00:00:00 2001 From: Bill Janssen Date: Wed, 5 Sep 2007 00:46:27 +0000 Subject: SSL certificate distinguished names should be represented by tuples --- Doc/library/ssl.rst | 81 +++++++++++++++++++++++++++++----------------------- Lib/test/test_ssl.py | 13 ++++----- Modules/_ssl.c | 25 +++++++++------- 3 files changed, 65 insertions(+), 54 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 8441eff..bd67644 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -173,6 +173,8 @@ use the first chain it finds in the file which matches. Some "standard" root certificates are available at http://www.thawte.com/roots/ (for Thawte roots) and http://www.verisign.com/support/roots.html (for Verisign roots). +See also :rfc:`4158` for more discussion of the way in which +certification chains can be built. sslsocket Objects @@ -242,23 +244,23 @@ sslsocket Objects the certificate), ``notBefore`` (the time before which the certificate should not be trusted), and ``notAfter`` (the time after which the certificate should not be trusted) filled in. - The "subject" and "issuer" fields are themselves dictionaries containing the fields given - in the certificate's data structure for each principal:: - - {'issuer': {'commonName': u'somemachine.python.org', - 'countryName': u'US', - 'localityName': u'Wilmington', - 'organizationName': u'Python Software Foundation', - 'organizationalUnitName': u'SSL', - 'stateOrProvinceName': u'Delaware'}, - 'subject': {'commonName': u'somemachine.python.org', - 'countryName': u'US', - 'localityName': u'Wilmington', - 'organizationName': u'Python Software Foundation', - 'organizationalUnitName': u'SSL', - 'stateOrProvinceName': u'Delaware'}, - 'notAfter': 'Sep 4 21:54:26 2007 GMT', - 'notBefore': 'Aug 25 21:54:26 2007 GMT', + The "subject" and "issuer" fields are tuples containing the name-value fields + given in the certificate's data structure for each principal:: + + {'issuer': (('countryName', u'US'), + ('stateOrProvinceName', u'Delaware'), + ('localityName', u'Wilmington'), + ('organizationName', u'Python Software Foundation'), + ('organizationalUnitName', u'SSL'), + ('commonName', u'somemachine.python.org')), + 'notAfter': 'Feb 16 16:54:50 2013 GMT', + 'notBefore': 'Aug 27 16:54:50 2007 GMT', + 'subject': (('countryName', u'US'), + ('stateOrProvinceName', u'Delaware'), + ('localityName', u'Wilmington'), + ('organizationName', u'Python Software Foundation'), + ('organizationalUnitName', u'SSL'), + ('commonName', u'somemachine.python.org')), 'version': 2} This certificate is said to be *self-signed*, because the subject @@ -314,27 +316,32 @@ sends some bytes, and reads part of the response:: # note that closing the sslsocket will also close the underlying socket ssl_sock.close() -As of August 25, 2007, the certificate printed by this program +As of September 4, 2007, the certificate printed by this program looked like this:: - {'issuer': {'commonName': u'VeriSign Class 3 Extended Validation SSL SGC CA', - 'countryName': u'US', - 'organizationName': u'VeriSign, Inc.', - 'organizationalUnitName': u'Terms of use at https://www.verisign.com/rpa (c)06'}, - 'subject': {'1.3.6.1.4.1.311.60.2.1.2': u'Delaware', - '1.3.6.1.4.1.311.60.2.1.3': u'US', - 'commonName': u'www.verisign.com', - 'countryName': u'US', - 'localityName': u'Mountain View', - 'organizationName': u'VeriSign, Inc.', - 'organizationalUnitName': u'Terms of use at www.verisign.com/rpa (c)06', - 'postalCode': u'94043', - 'serialNumber': u'2497886', - 'stateOrProvinceName': u'California', - 'streetAddress': u'487 East Middlefield Road'}, - 'notAfter': 'May 8 23:59:59 2009 GMT', - 'notBefore': 'May 9 00:00:00 2007 GMT', - 'version': 2} + {'issuer': (('countryName', u'US'), + ('organizationName', u'VeriSign, Inc.'), + ('organizationalUnitName', u'VeriSign Trust Network'), + ('organizationalUnitName', + u'Terms of use at https://www.verisign.com/rpa (c)06'), + ('commonName', + u'VeriSign Class 3 Extended Validation SSL SGC CA')), + 'notAfter': 'May 8 23:59:59 2009 GMT', + 'notBefore': 'May 9 00:00:00 2007 GMT', + 'subject': (('serialNumber', u'2497886'), + ('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'), + ('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'), + ('organizationalUnitName', + u'Terms of use at www.verisign.com/rpa (c)06'), + ('commonName', u'www.verisign.com')), + 'version': 2} Server-side operation ^^^^^^^^^^^^^^^^^^^^^ @@ -386,3 +393,5 @@ Class :class:`socket.socket` `Introducing SSL and Certificates using OpenSSL `_, by Frederick J. Hirsch `Privacy Enhancement for Internet Electronic Mail: Part II: Certificate-Based Key Management`, :rfc:`1422`, by Steve Kent + +`Internet X.509 Public Key Infrastructure Certificate and CRL Profile`, :rfc:`3280`, Housley et. al. diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 35c6af9..04daab2 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -137,18 +137,15 @@ class ConnectedTests(unittest.TestCase): cert = c2.getpeercert() if not cert: raise test_support.TestFailed("Can't get peer certificate.") + if test_support.verbose: + sys.stdout.write(pprint.pformat(cert) + '\n') if not cert.has_key('subject'): raise test_support.TestFailed( "No subject field in certificate: %s." % pprint.pformat(cert)) - if not (cert['subject'].has_key('organizationName')): - raise test_support.TestFailed( - "No 'organizationName' field in certificate subject: %s." % - pprint.pformat(cert)) - if (cert['subject']['organizationName'] != - "Python Software Foundation"): + if not ('organizationName', 'Python Software Foundation') in cert['subject']: raise test_support.TestFailed( - "Invalid 'organizationName' field in certificate subject; " + "Missing or invalid 'organizationName' field in certificate subject; " "should be 'Python Software Foundation'."); c2.close() @@ -336,7 +333,7 @@ def create_cert_files(hostname=None): def test_main(verbose=False): if skip_expected: - raise test_support.TestSkipped("socket module has no ssl support") + raise test_support.TestSkipped("No SSL support") global CERTFILE CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, diff --git a/Modules/_ssl.c b/Modules/_ssl.c index a1c2380..a34c3c8 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -437,12 +437,15 @@ PySSL_issuer(PySSLObject *self) } static PyObject * -_create_dict_for_X509_NAME (X509_NAME *xname) +_create_tuple_for_X509_NAME (X509_NAME *xname) { - PyObject *pd = PyDict_New(); + PyObject *pt = NULL; + PyObject *entry_tuple = NULL; + int entry_count = X509_NAME_entry_count(xname); int index_counter; - if (pd == NULL) + pt = PyTuple_New(entry_count); + if (pt == NULL) return NULL; for (index_counter = 0; @@ -480,18 +483,20 @@ _create_dict_for_X509_NAME (X509_NAME *xname) Py_DECREF(name_obj); goto fail0; } - if (PyDict_SetItem(pd, name_obj, value_obj) < 0) { + entry_tuple = PyTuple_New(2); + if (entry_tuple == NULL) { Py_DECREF(name_obj); Py_DECREF(value_obj); goto fail0; } - Py_DECREF(name_obj); - Py_DECREF(value_obj); + PyTuple_SET_ITEM(entry_tuple, 0, name_obj); + PyTuple_SET_ITEM(entry_tuple, 1, value_obj); + PyTuple_SET_ITEM(pt, index_counter, entry_tuple); } - return pd; + return pt; fail0: - Py_XDECREF(pd); + Py_XDECREF(pt); return NULL; } @@ -520,7 +525,7 @@ PySSL_peercert(PySSLObject *self) if ((verification & SSL_VERIFY_PEER) == 0) return retval; - peer = _create_dict_for_X509_NAME( + peer = _create_tuple_for_X509_NAME( X509_get_subject_name(self->peer_cert)); if (peer == NULL) goto fail0; @@ -530,7 +535,7 @@ PySSL_peercert(PySSLObject *self) } Py_DECREF(peer); - issuer = _create_dict_for_X509_NAME( + issuer = _create_tuple_for_X509_NAME( X509_get_issuer_name(self->peer_cert)); if (issuer == NULL) goto fail0; -- cgit v0.12