diff -r 6d3e60be0eeb Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py Fri Nov 22 03:43:48 2013 +0100 +++ b/Lib/asyncio/selector_events.py Fri Nov 22 04:14:19 2013 +0100 @@ -571,10 +571,9 @@ # context; in that case the sslcontext passed is None. # The default is the same as used by urllib with # cadefault=True. - sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - sslcontext.options |= ssl.OP_NO_SSLv2 + sslcontext = ssl.create_default_context( + verify_mode=ssl.CERT_REQUIRED) sslcontext.set_default_verify_paths() - sslcontext.verify_mode = ssl.CERT_REQUIRED wrap_kwargs = { 'server_side': server_side, diff -r 6d3e60be0eeb Lib/ftplib.py --- a/Lib/ftplib.py Fri Nov 22 03:43:48 2013 +0100 +++ b/Lib/ftplib.py Fri Nov 22 04:14:19 2013 +0100 @@ -727,6 +727,10 @@ "exclusive") self.keyfile = keyfile self.certfile = certfile + if context is None: + context = ssl.create_default_context(self.ssl_version, + certfile=certfile, + keyfile=keyfile) self.context = context self._prot_p = False FTP.__init__(self, host, user, passwd, acct, timeout, source_address) @@ -744,12 +748,7 @@ resp = self.voidcmd('AUTH TLS') else: resp = self.voidcmd('AUTH SSL') - if self.context is not None: - self.sock = self.context.wrap_socket(self.sock) - else: - self.sock = ssl.wrap_socket(self.sock, self.keyfile, - self.certfile, - ssl_version=self.ssl_version) + self.sock = self.context.wrap_socket(self.sock) self.file = self.sock.makefile(mode='r', encoding=self.encoding) return resp @@ -788,11 +787,7 @@ def ntransfercmd(self, cmd, rest=None): conn, size = FTP.ntransfercmd(self, cmd, rest) if self._prot_p: - if self.context is not None: - conn = self.context.wrap_socket(conn) - else: - conn = ssl.wrap_socket(conn, self.keyfile, self.certfile, - ssl_version=self.ssl_version) + conn = self.context.wrap_socket(conn) return conn, size def abort(self): diff -r 6d3e60be0eeb Lib/http/client.py --- a/Lib/http/client.py Fri Nov 22 03:43:48 2013 +0100 +++ b/Lib/http/client.py Fri Nov 22 04:14:19 2013 +0100 @@ -1179,9 +1179,7 @@ self.key_file = key_file self.cert_file = cert_file if context is None: - # Some reasonable defaults - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - context.options |= ssl.OP_NO_SSLv2 + context = ssl.create_default_context() will_verify = context.verify_mode != ssl.CERT_NONE if check_hostname is None: check_hostname = will_verify diff -r 6d3e60be0eeb Lib/imaplib.py --- a/Lib/imaplib.py Fri Nov 22 03:43:48 2013 +0100 +++ b/Lib/imaplib.py Fri Nov 22 04:14:19 2013 +0100 @@ -742,9 +742,7 @@ raise self.abort('TLS not supported by server') # Generate a default SSL context if none was passed. if ssl_context is None: - ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - # SSLv2 considered harmful. - ssl_context.options |= ssl.OP_NO_SSLv2 + ssl_context = ssl.create_default_context() typ, dat = self._simple_command(name) if typ == 'OK': self.sock = ssl_context.wrap_socket(self.sock) @@ -1210,15 +1208,15 @@ self.keyfile = keyfile self.certfile = certfile + if ssl_context is None: + ssl_context = ssl.create_default_context(certfile=certfile, + keyfile=keyfile) self.ssl_context = ssl_context IMAP4.__init__(self, host, port) def _create_socket(self): sock = IMAP4._create_socket(self) - if self.ssl_context: - return self.ssl_context.wrap_socket(sock) - else: - return ssl.wrap_socket(sock, self.keyfile, self.certfile) + return self.ssl_context.wrap_socket(sock) def open(self, host='', port=IMAP4_SSL_PORT): """Setup connection to remote server on "host:port". diff -r 6d3e60be0eeb Lib/nntplib.py --- a/Lib/nntplib.py Fri Nov 22 03:43:48 2013 +0100 +++ b/Lib/nntplib.py Fri Nov 22 04:14:19 2013 +0100 @@ -288,9 +288,7 @@ """ # Generate a default SSL context if none was passed. if context is None: - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - # SSLv2 considered harmful. - context.options |= ssl.OP_NO_SSLv2 + context = ssl.create_default_context() return context.wrap_socket(sock) diff -r 6d3e60be0eeb Lib/poplib.py --- a/Lib/poplib.py Fri Nov 22 03:43:48 2013 +0100 +++ b/Lib/poplib.py Fri Nov 22 04:14:19 2013 +0100 @@ -385,8 +385,7 @@ if not 'STLS' in caps: raise error_proto('-ERR STLS not supported by server') if context is None: - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - context.options |= ssl.OP_NO_SSLv2 + context = ssl.create_default_context() resp = self._shortcmd('STLS') self.sock = context.wrap_socket(self.sock) self.file = self.sock.makefile('rb') @@ -421,15 +420,15 @@ "exclusive") self.keyfile = keyfile self.certfile = certfile + if context is None: + context = ssl.create_default_context(certfile=certfile, + keyfile=keyfile) self.context = context POP3.__init__(self, host, port, timeout) def _create_socket(self, timeout): sock = POP3._create_socket(self, timeout) - if self.context is not None: - sock = self.context.wrap_socket(sock) - else: - sock = ssl.wrap_socket(sock, self.keyfile, self.certfile) + sock = self.context.wrap_socket(sock) return sock def stls(self, keyfile=None, certfile=None, context=None): diff -r 6d3e60be0eeb Lib/smtplib.py --- a/Lib/smtplib.py Fri Nov 22 03:43:48 2013 +0100 +++ b/Lib/smtplib.py Fri Nov 22 04:14:19 2013 +0100 @@ -664,10 +664,10 @@ if context is not None and certfile is not None: raise ValueError("context and certfile arguments are mutually " "exclusive") - if context is not None: - self.sock = context.wrap_socket(self.sock) - else: - self.sock = ssl.wrap_socket(self.sock, keyfile, certfile) + if context is None: + context = ssl.create_default_context(certfile=certfile, + keyfile=keyfile) + self.sock = context.wrap_socket(self.sock) self.file = None # RFC 3207: # The client MUST discard any knowledge obtained from @@ -880,6 +880,9 @@ "exclusive") self.keyfile = keyfile self.certfile = certfile + if context is None: + context = ssl.create_default_context(certfile=self.certfile, + keyfile=self.keyfile) self.context = context SMTP.__init__(self, host, port, local_hostname, timeout, source_address) @@ -889,10 +892,7 @@ print('connect:', (host, port), file=stderr) new_socket = socket.create_connection((host, port), timeout, self.source_address) - if self.context is not None: - new_socket = self.context.wrap_socket(new_socket) - else: - new_socket = ssl.wrap_socket(new_socket, self.keyfile, self.certfile) + new_socket = self.context.wrap_socket(new_socket) return new_socket __all__.append("SMTP_SSL") diff -r 6d3e60be0eeb Lib/ssl.py --- a/Lib/ssl.py Fri Nov 22 03:43:48 2013 +0100 +++ b/Lib/ssl.py Fri Nov 22 04:14:19 2013 +0100 @@ -335,6 +335,23 @@ self._set_npn_protocols(protos) +def create_default_context(protocol=PROTOCOL_SSLv23, *, verify_mode=CERT_NONE, + certfile=None, keyfile=None): + """Create a SSLContext object with default settings. + + NOTE: The protocol and settings may change anytime without prior + deprecation. The values represent a fair balance between maximum + compatibility and security. + """ + context = SSLContext(protocol) + context.verify_mode = verify_mode + # SSLv2 considered harmful. + context.options |= OP_NO_SSLv2 + if certfile is not None or keyfile is not None: + context.load_cert_chain(certfile, keyfile) + return context + + class SSLSocket(socket): """This class implements a subtype of socket.socket that wraps the underlying OS socket in an SSL context when necessary, and diff -r 6d3e60be0eeb Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py Fri Nov 22 03:43:48 2013 +0100 +++ b/Lib/test/test_ssl.py Fri Nov 22 04:14:19 2013 +0100 @@ -604,6 +604,29 @@ expected) self.assertRaises(ValueError, ssl._ASN1Object.fromname, 'serverauth') + def test_create_default_context(self): + ctx = ssl.create_default_context() + self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) + self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) + self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) + + ctx = ssl.create_default_context(ssl.PROTOCOL_TLSv1) + self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) + self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) + self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) + + ctx = ssl.create_default_context(ssl.PROTOCOL_TLSv1_1, + verify_mode=ssl.CERT_REQUIRED) + self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1_1) + self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) + self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) + + ctx = ssl.create_default_context(certfile=CERTFILE) + ctx = ssl.create_default_context(certfile=ONLYCERT, + keyfile=ONLYKEY) + with self.assertRaises(FileNotFoundError): + ssl.create_default_context(certfile=WRONGCERT) + class ContextTests(unittest.TestCase): diff -r 6d3e60be0eeb Lib/urllib/request.py --- a/Lib/urllib/request.py Fri Nov 22 03:43:48 2013 +0100 +++ b/Lib/urllib/request.py Fri Nov 22 04:14:19 2013 +0100 @@ -141,9 +141,7 @@ if cafile or capath or cadefault: if not _have_ssl: raise ValueError('SSL support not available') - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - context.options |= ssl.OP_NO_SSLv2 - context.verify_mode = ssl.CERT_REQUIRED + context = ssl.create_default_context(verify_mode=ssl.CERT_REQUIRED) if cafile or capath: context.load_verify_locations(cafile, capath) else: