From 04f6a32dff60d6f22b56b887338dd6ebbdc68dfe Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Mon, 5 Apr 2010 21:40:07 +0000 Subject: [PATCH] Merged revisions 79812 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r79812 | antoine.pitrou | 2010-04-05 23:35:07 +0200 (lun., 05 avril 2010) | 5 lines Issue #8321: Give access to OpenSSL version numbers from the `ssl` module, using the new attributes `ssl.OPENSSL_VERSION`, `ssl.OPENSSL_VERSION_INFO` and `ssl.OPENSSL_VERSION_NUMBER`. ........ --- Doc/library/ssl.rst | 30 ++++++++++++++++++++++++++++++ Lib/ssl.py | 1 + Lib/test/test_ssl.py | 28 ++++++++++++++++++++++++++++ Misc/NEWS | 4 ++++ Modules/_ssl.c | 31 ++++++++++++++++++++++++++++++- 5 files changed, 93 insertions(+), 1 deletion(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 905fae0eafd..587df66d61d 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -237,6 +237,36 @@ Functions, Constants, and Exceptions modern version, and probably the best choice for maximum protection, if both sides can speak it. +.. data:: OPENSSL_VERSION + + The version string of the OpenSSL library loaded by the interpreter:: + + >>> ssl.OPENSSL_VERSION + 'OpenSSL 0.9.8k 25 Mar 2009' + + .. versionadded:: 2.7 + +.. data:: OPENSSL_VERSION_INFO + + A tuple of five integers representing version information about the + OpenSSL library:: + + >>> ssl.OPENSSL_VERSION_INFO + (0, 9, 8, 11, 15) + + .. versionadded:: 2.7 + +.. data:: OPENSSL_VERSION_NUMBER + + The raw version number of the OpenSSL library, as a single integer:: + + >>> ssl.OPENSSL_VERSION_NUMBER + 9470143L + >>> hex(ssl.OPENSSL_VERSION_NUMBER) + '0x9080bfL' + + .. versionadded:: 2.7 + SSLSocket Objects ----------------- diff --git a/Lib/ssl.py b/Lib/ssl.py index ebb11b49c56..75f542d44ab 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -58,6 +58,7 @@ import textwrap import _ssl # if we can't import it, let the error propagate +from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION from _ssl import SSLError from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED from _ssl import (PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23, diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 8d6d742be4c..1804fcd655a 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -94,6 +94,34 @@ class BasicTests(unittest.TestCase): if (d1 != d2): raise support.TestFailed("PEM-to-DER or DER-to-PEM translation failed") + def test_openssl_version(self): + n = ssl.OPENSSL_VERSION_NUMBER + t = ssl.OPENSSL_VERSION_INFO + s = ssl.OPENSSL_VERSION + self.assertIsInstance(n, int) + self.assertIsInstance(t, tuple) + self.assertIsInstance(s, str) + # Some sanity checks follow + # >= 0.9 + self.assertGreaterEqual(n, 0x900000) + # < 2.0 + self.assertLess(n, 0x20000000) + major, minor, fix, patch, status = t + self.assertGreaterEqual(major, 0) + self.assertLess(major, 2) + self.assertGreaterEqual(minor, 0) + self.assertLess(minor, 256) + self.assertGreaterEqual(fix, 0) + self.assertLess(fix, 256) + self.assertGreaterEqual(patch, 0) + self.assertLessEqual(patch, 26) + self.assertGreaterEqual(status, 0) + self.assertLessEqual(status, 15) + # Version string as returned by OpenSSL, the format might change + self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)), + (s, t)) + + class NetworkedTests(unittest.TestCase): def testConnect(self): diff --git a/Misc/NEWS b/Misc/NEWS index c11f3c7a498..de8d9f7878d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -303,6 +303,10 @@ C-API Library ------- +- Issue #8321: Give access to OpenSSL version numbers from the `ssl` module, + using the new attributes `ssl.OPENSSL_VERSION`, `ssl.OPENSSL_VERSION_INFO` + and `ssl.OPENSSL_VERSION_NUMBER`. + - Add functools.total_ordering() and functools.cmp_to_key(). - Issue #8257: The Decimal construct now accepts a float instance diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 66fd626602f..a41fd17cc71 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1636,7 +1636,9 @@ static struct PyModuleDef _sslmodule = { PyMODINIT_FUNC PyInit__ssl(void) { - PyObject *m, *d; + PyObject *m, *d, *r; + unsigned long libver; + unsigned int major, minor, fix, patch, status; PySocketModule_APIObject *socket_api; if (PyType_Ready(&PySSL_Type) < 0) @@ -1710,5 +1712,32 @@ PyInit__ssl(void) PY_SSL_VERSION_SSL23); PyModule_AddIntConstant(m, "PROTOCOL_TLSv1", PY_SSL_VERSION_TLS1); + + /* OpenSSL version */ + /* SSLeay() gives us the version of the library linked against, + which could be different from the headers version. + */ + libver = SSLeay(); + r = PyLong_FromUnsignedLong(libver); + if (r == NULL) + return NULL; + if (PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) + return NULL; + status = libver & 0xF; + libver >>= 4; + patch = libver & 0xFF; + libver >>= 8; + fix = libver & 0xFF; + libver >>= 8; + minor = libver & 0xFF; + libver >>= 8; + major = libver & 0xFF; + r = Py_BuildValue("IIIII", major, minor, fix, patch, status); + if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) + return NULL; + r = PyUnicode_FromString(SSLeay_version(SSLEAY_VERSION)); + if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) + return NULL; + return m; }