Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(2696)

Delta Between Two Patch Sets: Lib/ssl.py

Issue 19689: ssl.create_default_context()
Left Patch Set: Created 5 years, 6 months ago
Right Patch Set: Created 5 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Lib/smtplib.py ('k') | Lib/test/test_ssl.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # Wrapper module for _ssl, providing some additional facilities 1 # Wrapper module for _ssl, providing some additional facilities
2 # implemented in Python. Written by Bill Janssen. 2 # implemented in Python. Written by Bill Janssen.
3 3
4 """This module provides some more Pythonic support for SSL. 4 """This module provides some more Pythonic support for SSL.
5 5
6 Object types: 6 Object types:
7 7
8 SSLSocket -- subtype of socket.socket which does SSL over the socket 8 SSLSocket -- subtype of socket.socket which does SSL over the socket
9 9
10 Exceptions: 10 Exceptions:
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE 85 ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE
86 ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE 86 ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE
87 ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY 87 ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY
88 """ 88 """
89 89
90 import textwrap 90 import textwrap
91 import re 91 import re
92 import sys 92 import sys
93 import os 93 import os
94 from collections import namedtuple 94 from collections import namedtuple
95 import enum as _enum
95 96
96 import _ssl # if we can't import it, let the error propagate 97 import _ssl # if we can't import it, let the error propagate
97 98
98 from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION 99 from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION
99 from _ssl import _SSLContext 100 from _ssl import _SSLContext
100 from _ssl import ( 101 from _ssl import (
101 SSLError, SSLZeroReturnError, SSLWantReadError, SSLWantWriteError, 102 SSLError, SSLZeroReturnError, SSLWantReadError, SSLWantWriteError,
102 SSLSyscallError, SSLEOFError, 103 SSLSyscallError, SSLEOFError,
103 ) 104 )
104 from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED 105 from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 """ 292 """
292 return super().__new__(cls, *_nid2obj(nid)) 293 return super().__new__(cls, *_nid2obj(nid))
293 294
294 @classmethod 295 @classmethod
295 def fromname(cls, name): 296 def fromname(cls, name):
296 """Create _ASN1Object from short name, long name or OID 297 """Create _ASN1Object from short name, long name or OID
297 """ 298 """
298 return super().__new__(cls, *_txt2obj(name, name=True)) 299 return super().__new__(cls, *_txt2obj(name, name=True))
299 300
300 301
302 class PurposeEKU(_ASN1Object, _enum.Enum):
303 """X509v3 Extended Key Usage objects
304 """
305 serverAuth = '1.3.6.1.5.5.7.3.1'
306 clientAuth = '1.3.6.1.5.5.7.3.2'
307 #codeSigning = '1.3.6.1.5.5.7.3.3'
308 #emailProtection = '1.3.6.1.5.5.7.3.4'
309 #ipsecEndSystem = '1.3.6.1.5.5.7.3.5'
310 #ipsecTunnel = '1.3.6.1.5.5.7.3.6'
311 #ipsecUser = '1.3.6.1.5.5.7.3.7'
312 #timeStamping = '1.3.6.1.5.5.7.3.8'
313 #OCSPSigning = '1.3.6.1.5.5.7.3.9'
314 #DVCS = '1.3.6.1.5.5.7.3.10'
315 #nsSGC = '2.16.840.1.113730.4.1'
316 #msSGC = '1.3.6.1.4.1.311.10.3.3'
317
318
301 class SSLContext(_SSLContext): 319 class SSLContext(_SSLContext):
302 """An SSLContext holds various SSL-related configuration options and 320 """An SSLContext holds various SSL-related configuration options and
303 data, such as certificates and possibly a private key.""" 321 data, such as certificates and possibly a private key."""
304 322
305 __slots__ = ('protocol', '__weakref__') 323 __slots__ = ('protocol', '__weakref__')
306 324
307 def __new__(cls, protocol, *args, **kwargs): 325 def __new__(cls, protocol, *args, **kwargs):
308 self = _SSLContext.__new__(cls, protocol) 326 self = _SSLContext.__new__(cls, protocol)
309 if protocol != _SSLv2_IF_EXISTS: 327 if protocol != _SSLv2_IF_EXISTS:
310 self.set_ciphers(_DEFAULT_CIPHERS) 328 self.set_ciphers(_DEFAULT_CIPHERS)
(...skipping 16 matching lines...) Expand all
327 protos = bytearray() 345 protos = bytearray()
328 for protocol in npn_protocols: 346 for protocol in npn_protocols:
329 b = bytes(protocol, 'ascii') 347 b = bytes(protocol, 'ascii')
330 if len(b) == 0 or len(b) > 255: 348 if len(b) == 0 or len(b) > 255:
331 raise SSLError('NPN protocols must be 1 to 255 in length') 349 raise SSLError('NPN protocols must be 1 to 255 in length')
332 protos.append(len(b)) 350 protos.append(len(b))
333 protos.extend(b) 351 protos.extend(b)
334 352
335 self._set_npn_protocols(protos) 353 self._set_npn_protocols(protos)
336 354
337 355 def load_default_certs(self, purpose):
338 def create_default_context(protocol=PROTOCOL_SSLv23, *, verify_mode=CERT_NONE, 356 if not isinstance(purpose, _ASN1Object):
339 certfile=None, keyfile=None): 357 raise TypeError(purpose)
358 self.set_default_verify_paths()
359
360
361 def create_default_context(protocol=PROTOCOL_SSLv23, *, cert_reqs=None,
362 purpose=PurposeEKU.serverAuth,
363 certfile=None, keyfile=None,
364 cafile=None, capath=None, cadata=None):
340 """Create a SSLContext object with default settings. 365 """Create a SSLContext object with default settings.
341 366
342 NOTE: The protocol and settings may change anytime without prior 367 NOTE: The protocol and settings may change anytime without prior
343 deprecation. The values represent a fair balance between maximum 368 deprecation. The values represent a fair balance between maximum
344 compatibility and security. 369 compatibility and security.
345 """ 370 """
371 if not isinstance(purpose, _ASN1Object):
372 raise TypeError(purpose)
373
346 context = SSLContext(protocol) 374 context = SSLContext(protocol)
347 context.verify_mode = verify_mode
348 # SSLv2 considered harmful. 375 # SSLv2 considered harmful.
349 context.options |= OP_NO_SSLv2 376 context.options |= OP_NO_SSLv2
350 if certfile is not None or keyfile is not None: 377
378 if cert_reqs is None:
379 if purpose == PurposeEKU.serverAuth:
380 # authenticate a TLS web server (for client sockets). The default
381 # setting may change in the future.
382 cert_reqs = CERT_NONE
383 elif purpose == PurposeEKU.clientAuth:
384 # authenticate a TLS web client (for server sockets). The default
385 # setting is guaranteed to be stable and will never change.
386 cert_reqs = CERT_NONE
387 else:
388 # other (code signing, S/MIME, IPSEC, ...), default may change.
389 cert_reqs = CERT_NONE
390 context.verify_mode = cert_reqs
391
392 # load cert file and key file
393 if certfile or keyfile:
351 context.load_cert_chain(certfile, keyfile) 394 context.load_cert_chain(certfile, keyfile)
395
396 # load CA root certs
397 if cafile or capath or cadata:
398 context.load_verify_locations(cafile, capath, cadata)
399 elif cert_reqs != CERT_NONE and purpose is not None:
400 # no explicit cafile, capath or cadata but the verify mode is
401 # CERT_OPTIONAL or CERT_REQUIRED. Let's try to load default system
402 # root CA certificates for the given purpose. This may fail silently.
403 context.load_default_certs(purpose)
404
352 return context 405 return context
353 406
354 407
355 class SSLSocket(socket): 408 class SSLSocket(socket):
356 """This class implements a subtype of socket.socket that wraps 409 """This class implements a subtype of socket.socket that wraps
357 the underlying OS socket in an SSL context when necessary, and 410 the underlying OS socket in an SSL context when necessary, and
358 provides read and write methods over that channel.""" 411 provides read and write methods over that channel."""
359 412
360 def __init__(self, sock=None, keyfile=None, certfile=None, 413 def __init__(self, sock=None, keyfile=None, certfile=None,
361 server_side=False, cert_reqs=CERT_NONE, 414 server_side=False, cert_reqs=CERT_NONE,
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 822
770 if not pem_cert_string.startswith(PEM_HEADER): 823 if not pem_cert_string.startswith(PEM_HEADER):
771 raise ValueError("Invalid PEM encoding; must start with %s" 824 raise ValueError("Invalid PEM encoding; must start with %s"
772 % PEM_HEADER) 825 % PEM_HEADER)
773 if not pem_cert_string.strip().endswith(PEM_FOOTER): 826 if not pem_cert_string.strip().endswith(PEM_FOOTER):
774 raise ValueError("Invalid PEM encoding; must end with %s" 827 raise ValueError("Invalid PEM encoding; must end with %s"
775 % PEM_FOOTER) 828 % PEM_FOOTER)
776 d = pem_cert_string.strip()[len(PEM_HEADER):-len(PEM_FOOTER)] 829 d = pem_cert_string.strip()[len(PEM_HEADER):-len(PEM_FOOTER)]
777 return base64.decodebytes(d.encode('ASCII', 'strict')) 830 return base64.decodebytes(d.encode('ASCII', 'strict'))
778 831
779 def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None): 832 def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None,
833 cert_reqs=None):
780 """Retrieve the certificate from the server at the specified address, 834 """Retrieve the certificate from the server at the specified address,
781 and return it as a PEM-encoded string. 835 and return it as a PEM-encoded string.
782 If 'ca_certs' is specified, validate the server cert against it. 836 If 'ca_certs' is specified, validate the server cert against it.
783 If 'ssl_version' is specified, use it in the connection attempt.""" 837 If 'ssl_version' is specified, use it in the connection attempt."""
784 838
785 host, port = addr 839 host, port = addr
786 if (ca_certs is not None): 840 if ca_certs is not None:
787 cert_reqs = CERT_REQUIRED 841 cert_reqs = CERT_REQUIRED
788 else: 842 context = create_default_context(ssl_version,
789 cert_reqs = CERT_NONE 843 cert_reqs=cert_reqs,
790 s = create_connection(addr) 844 cafile=ca_certs)
791 s = wrap_socket(s, ssl_version=ssl_version, 845 with create_connection(addr) as sock:
792 cert_reqs=cert_reqs, ca_certs=ca_certs) 846 with context.wrap_socket(sock) as sslsock:
793 dercert = s.getpeercert(True) 847 dercert = sslsock.getpeercert(True)
794 s.close()
795 return DER_cert_to_PEM_cert(dercert) 848 return DER_cert_to_PEM_cert(dercert)
796 849
797 def get_protocol_name(protocol_code): 850 def get_protocol_name(protocol_code):
798 return _PROTOCOL_NAMES.get(protocol_code, '<unknown>') 851 return _PROTOCOL_NAMES.get(protocol_code, '<unknown>')
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+