diff options
Diffstat (limited to 'Doc/library/ssl.rst')
| -rw-r--r-- | Doc/library/ssl.rst | 744 |
1 files changed, 593 insertions, 151 deletions
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 19b90a1..0f5cea2 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -12,8 +12,6 @@ .. index:: TLS, SSL, Transport Layer Security, Secure Sockets Layer -.. versionadded:: 2.6 - **Source code:** :source:`Lib/ssl.py` -------------- @@ -37,23 +35,43 @@ the documents in the "See Also" section at the bottom. This module provides a class, :class:`ssl.SSLSocket`, which is derived from the :class:`socket.socket` type, and provides a socket-like wrapper that also encrypts and decrypts the data going over the socket with SSL. It supports -additional :meth:`read` and :meth:`write` methods, along with a method, -:meth:`getpeercert`, to retrieve the certificate of the other side of the -connection, and a method, :meth:`cipher`, to retrieve the cipher being used for -the secure connection. +additional methods such as :meth:`getpeercert`, which retrieves the +certificate of the other side of the connection, and :meth:`cipher`,which +retrieves the cipher being used for the secure connection. + +For more sophisticated applications, the :class:`ssl.SSLContext` class +helps manage settings and certificates, which can then be inherited +by SSL sockets created through the :meth:`SSLContext.wrap_socket` method. + Functions, Constants, and Exceptions ------------------------------------ .. exception:: SSLError - Raised to signal an error from the underlying SSL implementation. This - signifies some problem in the higher-level encryption and authentication - layer that's superimposed on the underlying network connection. This error + Raised to signal an error from the underlying SSL implementation + (currently provided by the OpenSSL library). This signifies some + problem in the higher-level encryption and authentication layer that's + superimposed on the underlying network connection. This error is a subtype of :exc:`socket.error`, which in turn is a subtype of - :exc:`IOError`. + :exc:`IOError`. The error code and message of :exc:`SSLError` instances + are provided by the OpenSSL library. + +.. exception:: CertificateError + + Raised to signal an error with a certificate (such as mismatching + hostname). Certificate errors detected by OpenSSL, though, raise + an :exc:`SSLError`. + + +Socket creation +^^^^^^^^^^^^^^^ + +The following function allows for standalone socket creation. Starting from +Python 3.2, it can be more flexible to use :meth:`SSLContext.wrap_socket` +instead. -.. function:: wrap_socket (sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None) +.. function:: wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None) Takes an instance ``sock`` of :class:`socket.socket`, and returns an instance of :class:`ssl.SSLSocket`, a subtype of :class:`socket.socket`, which wraps @@ -70,19 +88,6 @@ Functions, Constants, and Exceptions connection. See the discussion of :ref:`ssl-certificates` for more information on how the certificate is stored in the ``certfile``. - Often the private key is stored in the same file as the certificate; in this - case, only the ``certfile`` parameter need be passed. If the private key is - stored in a separate file, both parameters must be used. If the private key - is stored in the ``certfile``, it should come before the first certificate in - the certificate chain:: - - -----BEGIN RSA PRIVATE KEY----- - ... (private key in base64 encoding) ... - -----END RSA PRIVATE KEY----- - -----BEGIN CERTIFICATE----- - ... (certificate in base64 PEM encoding) ... - -----END CERTIFICATE----- - The parameter ``server_side`` is a boolean which identifies whether server-side or client-side behavior is desired from this socket. @@ -144,14 +149,18 @@ Functions, Constants, and Exceptions blocking behavior of the socket I/O involved in the handshake. The parameter ``suppress_ragged_eofs`` specifies how the - :meth:`SSLSocket.read` method should signal unexpected EOF from the other end + :meth:`SSLSocket.recv` method should signal unexpected EOF from the other end of the connection. If specified as :const:`True` (the default), it returns a - normal EOF in response to unexpected EOF errors raised from the underlying - socket; if :const:`False`, it will raise the exceptions back to the caller. + normal EOF (an empty bytes object) in response to unexpected EOF errors + raised from the underlying socket; if :const:`False`, it will raise the + exceptions back to the caller. - .. versionchanged:: 2.7 + .. versionchanged:: 3.2 New optional argument *ciphers*. +Random generation +^^^^^^^^^^^^^^^^^ + .. function:: RAND_status() Returns True if the SSL pseudo-random number generator has been seeded with @@ -177,6 +186,32 @@ Functions, Constants, and Exceptions string (so you can always use :const:`0.0`). See :rfc:`1750` for more information on sources of entropy. +Certificate handling +^^^^^^^^^^^^^^^^^^^^ + +.. function:: match_hostname(cert, hostname) + + Verify that *cert* (in decoded format as returned by + :meth:`SSLSocket.getpeercert`) matches the given *hostname*. The rules + applied are those for checking the identity of HTTPS servers as outlined + in :rfc:`2818`, except that IP addresses are not currently supported. + In addition to HTTPS, this function should be suitable for checking the + identity of servers in various SSL-based protocols such as FTPS, IMAPS, + POPS and others. + + :exc:`CertificateError` is raised on failure. On success, the function + returns nothing:: + + >>> cert = {'subject': ((('commonName', 'example.com'),),)} + >>> ssl.match_hostname(cert, "example.com") + >>> ssl.match_hostname(cert, "example.org") + Traceback (most recent call last): + File "<stdin>", line 1, in <module> + File "/home/py3k/Lib/ssl.py", line 130, in match_hostname + ssl.CertificateError: hostname 'example.org' doesn't match 'example.com' + + .. versionadded:: 3.2 + .. function:: cert_time_to_seconds(timestring) Returns a floating-point value containing a normal seconds-after-the-epoch @@ -191,9 +226,8 @@ Functions, Constants, and Exceptions >>> import time >>> time.ctime(ssl.cert_time_to_seconds("May 9 00:00:00 2007 GMT")) 'Wed May 9 00:00:00 2007' - >>> -.. function:: get_server_certificate (addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None) +.. function:: get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None) Given the address ``addr`` of an SSL-protected server, as a (*hostname*, *port-number*) pair, fetches the server's certificate, and returns it as a @@ -204,36 +238,51 @@ Functions, Constants, and Exceptions will attempt to validate the server certificate against that set of root certificates, and will fail if the validation attempt fails. -.. function:: DER_cert_to_PEM_cert (DER_cert_bytes) +.. function:: DER_cert_to_PEM_cert(DER_cert_bytes) Given a certificate as a DER-encoded blob of bytes, returns a PEM-encoded string version of the same certificate. -.. function:: PEM_cert_to_DER_cert (PEM_cert_string) +.. function:: PEM_cert_to_DER_cert(PEM_cert_string) Given a certificate as an ASCII PEM string, returns a DER-encoded sequence of bytes for that same certificate. +Constants +^^^^^^^^^ + .. data:: CERT_NONE - Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when no - certificates will be required or validated from the other side of the socket - connection. + Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs`` + parameter to :func:`wrap_socket`. In this mode (the default), no + certificates will be required from the other side of the socket connection. + If a certificate is received from the other end, no attempt to validate it + is made. + + See the discussion of :ref:`ssl-security` below. .. data:: CERT_OPTIONAL - Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when no - certificates will be required from the other side of the socket connection, - but if they are provided, will be validated. Note that use of this setting - requires a valid certificate validation file also be passed as a value of the - ``ca_certs`` parameter. + Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs`` + parameter to :func:`wrap_socket`. In this mode no certificates will be + required from the other side of the socket connection; but if they + are provided, validation will be attempted and an :class:`SSLError` + will be raised on failure. + + Use of this setting requires a valid set of CA certificates to + be passed, either to :meth:`SSLContext.load_verify_locations` or as a + value of the ``ca_certs`` parameter to :func:`wrap_socket`. .. data:: CERT_REQUIRED - Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when - certificates will be required from the other side of the socket connection. - Note that use of this setting requires a valid certificate validation file - also be passed as a value of the ``ca_certs`` parameter. + Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs`` + parameter to :func:`wrap_socket`. In this mode, certificates are + required from the other side of the socket connection; an :class:`SSLError` + will be raised if no certificate is provided, or if its validation fails. + + Use of this setting requires a valid set of CA certificates to + be passed, either to :meth:`SSLContext.load_verify_locations` or as a + value of the ``ca_certs`` parameter to :func:`wrap_socket`. .. data:: PROTOCOL_SSLv2 @@ -264,6 +313,47 @@ Functions, Constants, and Exceptions modern version, and probably the best choice for maximum protection, if both sides can speak it. +.. data:: OP_ALL + + Enables workarounds for various bugs present in other SSL implementations. + This option is set by default. It does not necessarily set the same + flags as OpenSSL's ``SSL_OP_ALL`` constant. + + .. versionadded:: 3.2 + +.. data:: OP_NO_SSLv2 + + Prevents an SSLv2 connection. This option is only applicable in + conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from + choosing SSLv2 as the protocol version. + + .. versionadded:: 3.2 + +.. data:: OP_NO_SSLv3 + + Prevents an SSLv3 connection. This option is only applicable in + conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from + choosing SSLv3 as the protocol version. + + .. versionadded:: 3.2 + +.. data:: OP_NO_TLSv1 + + Prevents a TLSv1 connection. This option is only applicable in + conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from + choosing TLSv1 as the protocol version. + + .. versionadded:: 3.2 + +.. data:: HAS_SNI + + Whether the OpenSSL library has built-in support for the *Server Name + Indication* extension to the SSLv3 and TLSv1 protocols (as defined in + :rfc:`4366`). When true, you can use the *server_hostname* argument to + :meth:`SSLContext.wrap_socket`. + + .. versionadded:: 3.2 + .. data:: OPENSSL_VERSION The version string of the OpenSSL library loaded by the interpreter:: @@ -271,7 +361,7 @@ Functions, Constants, and Exceptions >>> ssl.OPENSSL_VERSION 'OpenSSL 0.9.8k 25 Mar 2009' - .. versionadded:: 2.7 + .. versionadded:: 3.2 .. data:: OPENSSL_VERSION_INFO @@ -281,31 +371,53 @@ Functions, Constants, and Exceptions >>> ssl.OPENSSL_VERSION_INFO (0, 9, 8, 11, 15) - .. versionadded:: 2.7 + .. versionadded:: 3.2 .. data:: OPENSSL_VERSION_NUMBER The raw version number of the OpenSSL library, as a single integer:: >>> ssl.OPENSSL_VERSION_NUMBER - 9470143L + 9470143 >>> hex(ssl.OPENSSL_VERSION_NUMBER) - '0x9080bfL' + '0x9080bf' + + .. versionadded:: 3.2 - .. versionadded:: 2.7 +SSL Sockets +----------- -SSLSocket Objects ------------------ +SSL sockets provide the following methods of :ref:`socket-objects`: -.. method:: SSLSocket.read([nbytes=1024]) +- :meth:`~socket.socket.accept()` +- :meth:`~socket.socket.bind()` +- :meth:`~socket.socket.close()` +- :meth:`~socket.socket.connect()` +- :meth:`~socket.socket.detach()` +- :meth:`~socket.socket.fileno()` +- :meth:`~socket.socket.getpeername()`, :meth:`~socket.socket.getsockname()` +- :meth:`~socket.socket.getsockopt()`, :meth:`~socket.socket.setsockopt()` +- :meth:`~socket.socket.gettimeout()`, :meth:`~socket.socket.settimeout()`, + :meth:`~socket.socket.setblocking()` +- :meth:`~socket.socket.listen()` +- :meth:`~socket.socket.makefile()` +- :meth:`~socket.socket.recv()`, :meth:`~socket.socket.recv_into()` + (but passing a non-zero ``flags`` argument is not allowed) +- :meth:`~socket.socket.send()`, :meth:`~socket.socket.sendall()` (with + the same limitation) +- :meth:`~socket.socket.shutdown()` - Reads up to ``nbytes`` bytes from the SSL-encrypted channel and returns them. +However, since the SSL (and TLS) protocol has its own framing atop +of TCP, the SSL sockets abstraction can, in certain respects, diverge from +the specification of normal, OS-level sockets. See especially the +:ref:`notes on non-blocking sockets <ssl-nonblocking>`. -.. method:: SSLSocket.write(data) +SSL sockets also have the following additional methods and attributes: + +.. method:: SSLSocket.do_handshake() - Writes the ``data`` to the other side of the connection, using the SSL - channel to encrypt. Returns the number of bytes written. + Perform the SSL setup handshake. .. method:: SSLSocket.getpeercert(binary_form=False) @@ -315,25 +427,39 @@ SSLSocket Objects If the parameter ``binary_form`` is :const:`False`, and a certificate was received from the peer, this method returns a :class:`dict` instance. If the certificate was not validated, the dict is empty. If the certificate was - validated, it returns a dict with the keys ``subject`` (the principal for - which the certificate was issued), and ``notAfter`` (the time after which the - certificate should not be trusted). The certificate was already validated, - so the ``notBefore`` and ``issuer`` fields are not returned. If a - certificate contains an instance of the *Subject Alternative Name* extension - (see :rfc:`3280`), there will also be a ``subjectAltName`` key in the - dictionary. - - The "subject" field is a tuple containing the sequence of relative - distinguished names (RDNs) given in the certificate's data structure for the - principal, and each RDN is a sequence of name-value pairs:: - - {'notAfter': 'Feb 16 16:54:50 2013 GMT', - 'subject': ((('countryName', u'US'),), - (('stateOrProvinceName', u'Delaware'),), - (('localityName', u'Wilmington'),), - (('organizationName', u'Python Software Foundation'),), - (('organizationalUnitName', u'SSL'),), - (('commonName', u'somemachine.python.org'),))} + validated, it returns a dict with several keys, amongst them ``subject`` + (the principal for which the certificate was issued) and ``issuer`` + (the principal issuing the certificate). If a certificate contains an + instance of the *Subject Alternative Name* extension (see :rfc:`3280`), + there will also be a ``subjectAltName`` key in the dictionary. + + The ``subject`` and ``issuer`` fields are tuples containing the sequence + of relative distinguished names (RDNs) given in the certificate's data + structure for the respective fields, and each RDN is a sequence of + name-value pairs. Here is a real-world example:: + + {'issuer': ((('countryName', 'IL'),), + (('organizationName', 'StartCom Ltd.'),), + (('organizationalUnitName', + 'Secure Digital Certificate Signing'),), + (('commonName', + 'StartCom Class 2 Primary Intermediate Server CA'),)), + 'notAfter': 'Nov 22 08:15:19 2013 GMT', + 'notBefore': 'Nov 21 03:09:52 2011 GMT', + 'serialNumber': '95F0', + 'subject': ((('description', '571208-SLe257oHY9fVQ07Z'),), + (('countryName', 'US'),), + (('stateOrProvinceName', 'California'),), + (('localityName', 'San Francisco'),), + (('organizationName', 'Electronic Frontier Foundation, Inc.'),), + (('commonName', '*.eff.org'),), + (('emailAddress', 'hostmaster@eff.org'),)), + 'subjectAltName': (('DNS', '*.eff.org'), ('DNS', 'eff.org')), + 'version': 3} + + .. note:: + To validate a certificate for a particular service, you can use the + :func:`match_hostname` function. If the ``binary_form`` parameter is :const:`True`, and a certificate was provided, this method returns the DER-encoded form of the entire certificate @@ -343,40 +469,160 @@ SSLSocket Objects been validated, but if :const:`CERT_NONE` was used to establish the connection, the certificate, if present, will not have been validated. + .. versionchanged:: 3.2 + The returned dictionary includes additional items such as ``issuer`` + and ``notBefore``. + .. method:: SSLSocket.cipher() Returns a three-value tuple containing the name of the cipher being used, the version of the SSL protocol that defines its use, and the number of secret bits being used. If no connection has been established, returns ``None``. -.. method:: SSLSocket.do_handshake() - - Perform a TLS/SSL handshake. If this is used with a non-blocking socket, it - may raise :exc:`SSLError` with an ``arg[0]`` of :const:`SSL_ERROR_WANT_READ` - or :const:`SSL_ERROR_WANT_WRITE`, in which case it must be called again until - it completes successfully. For example, to simulate the behavior of a - blocking socket, one might write:: - - while True: - try: - s.do_handshake() - break - except ssl.SSLError as err: - if err.args[0] == ssl.SSL_ERROR_WANT_READ: - select.select([s], [], []) - elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: - select.select([], [s], []) - else: - raise .. method:: SSLSocket.unwrap() Performs the SSL shutdown handshake, which removes the TLS layer from the underlying socket, and returns the underlying socket object. This can be used to go from encrypted operation over a connection to unencrypted. The - socket instance returned should always be used for further communication with - the other side of the connection, rather than the original socket instance - (which may not function properly after the unwrap). + returned socket should always be used for further communication with the + other side of the connection, rather than the original socket. + + +.. attribute:: SSLSocket.context + + The :class:`SSLContext` object this SSL socket is tied to. If the SSL + socket was created using the top-level :func:`wrap_socket` function + (rather than :meth:`SSLContext.wrap_socket`), this is a custom context + object created for this SSL socket. + + .. versionadded:: 3.2 + + +SSL Contexts +------------ + +.. versionadded:: 3.2 + +An SSL context holds various data longer-lived than single SSL connections, +such as SSL configuration options, certificate(s) and private key(s). +It also manages a cache of SSL sessions for server-side sockets, in order +to speed up repeated connections from the same clients. + +.. class:: SSLContext(protocol) + + Create a new SSL context. You must pass *protocol* which must be one + of the ``PROTOCOL_*`` constants defined in this module. + :data:`PROTOCOL_SSLv23` is recommended for maximum interoperability. + + +:class:`SSLContext` objects have the following methods and attributes: + +.. method:: SSLContext.load_cert_chain(certfile, keyfile=None) + + Load a private key and the corresponding certificate. The *certfile* + string must be the path to a single file in PEM format containing the + certificate as well as any number of CA certificates needed to establish + the certificate's authenticity. The *keyfile* string, if present, must + point to a file containing the private key in. Otherwise the private + key will be taken from *certfile* as well. See the discussion of + :ref:`ssl-certificates` for more information on how the certificate + is stored in the *certfile*. + + An :class:`SSLError` is raised if the private key doesn't + match with the certificate. + +.. method:: SSLContext.load_verify_locations(cafile=None, capath=None) + + Load a set of "certification authority" (CA) certificates used to validate + other peers' certificates when :data:`verify_mode` is other than + :data:`CERT_NONE`. At least one of *cafile* or *capath* must be specified. + + The *cafile* string, if present, is the path to a file of concatenated + CA certificates in PEM format. See the discussion of + :ref:`ssl-certificates` for more information about how to arrange the + certificates in this file. + + The *capath* string, if present, is + the path to a directory containing several CA certificates in PEM format, + following an `OpenSSL specific layout + <http://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html>`_. + +.. method:: SSLContext.set_default_verify_paths() + + Load a set of default "certification authority" (CA) certificates from + a filesystem path defined when building the OpenSSL library. Unfortunately, + there's no easy way to know whether this method succeeds: no error is + returned if no certificates are to be found. When the OpenSSL library is + provided as part of the operating system, though, it is likely to be + configured properly. + +.. method:: SSLContext.set_ciphers(ciphers) + + Set the available ciphers for sockets created with this context. + It should be a string in the `OpenSSL cipher list format + <http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT>`_. + If no cipher can be selected (because compile-time options or other + configuration forbids use of all the specified ciphers), an + :class:`SSLError` will be raised. + + .. note:: + when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will + give the currently selected cipher. + +.. method:: SSLContext.wrap_socket(sock, server_side=False, \ + do_handshake_on_connect=True, suppress_ragged_eofs=True, \ + server_hostname=None) + + Wrap an existing Python socket *sock* and return an :class:`SSLSocket` + object. The SSL socket is tied to the context, its settings and + certificates. The parameters *server_side*, *do_handshake_on_connect* + and *suppress_ragged_eofs* have the same meaning as in the top-level + :func:`wrap_socket` function. + + On client connections, the optional parameter *server_hostname* specifies + the hostname of the service which we are connecting to. This allows a + single server to host multiple SSL-based services with distinct certificates, + quite similarly to HTTP virtual hosts. Specifying *server_hostname* + will raise a :exc:`ValueError` if the OpenSSL library doesn't have support + for it (that is, if :data:`HAS_SNI` is :const:`False`). Specifying + *server_hostname* will also raise a :exc:`ValueError` if *server_side* + is true. + +.. method:: SSLContext.session_stats() + + Get statistics about the SSL sessions created or managed by this context. + A dictionary is returned which maps the names of each `piece of information + <http://www.openssl.org/docs/ssl/SSL_CTX_sess_number.html>`_ to their + numeric values. For example, here is the total number of hits and misses + in the session cache since the context was created:: + + >>> stats = context.session_stats() + >>> stats['hits'], stats['misses'] + (0, 0) + +.. attribute:: SSLContext.options + + An integer representing the set of SSL options enabled on this context. + The default value is :data:`OP_ALL`, but you can specify other options + such as :data:`OP_NO_SSLv2` by ORing them together. + + .. note:: + With versions of OpenSSL older than 0.9.8m, it is only possible + to set options, not to clear them. Attempting to clear an option + (by resetting the corresponding bits) will raise a ``ValueError``. + +.. attribute:: SSLContext.protocol + + The protocol version chosen when constructing the context. This attribute + is read-only. + +.. attribute:: SSLContext.verify_mode + + Whether to try to verify other peers' certificates and how to behave + if verification fails. This attribute must be one of + :data:`CERT_NONE`, :data:`CERT_OPTIONAL` or :data:`CERT_REQUIRED`. + .. index:: single: certificates @@ -423,6 +669,9 @@ and a footer line:: ... (certificate in base64 PEM encoding) ... -----END CERTIFICATE----- +Certificate chains +^^^^^^^^^^^^^^^^^^ + The Python files which contain certificates can contain a sequence of certificates, sometimes called a *certificate chain*. This chain should start with the specific certificate for the principal who "is" the client or server, @@ -446,14 +695,16 @@ certification authority's certificate:: ... (the root certificate for the CA's issuer)... -----END CERTIFICATE----- +CA certificates +^^^^^^^^^^^^^^^ + If you are going to require validation of the other side of the connection's certificate, you need to provide a "CA certs" file, filled with the certificate chains for each issuer you are willing to trust. Again, this file just contains these chains concatenated together. For validation, Python will use the first -chain it finds in the file which matches. - -Some "standard" root certificates are available from various certification -authorities: `CACert.org <http://www.cacert.org/index.php?id=3>`_, `Thawte +chain it finds in the file which matches. Some "standard" root certificates are +available from various certification authorities: `CACert.org +<http://www.cacert.org/index.php?id=3>`_, `Thawte <http://www.thawte.com/roots/>`_, `Verisign <http://www.verisign.com/support/roots.html>`_, `Positive SSL <http://www.PositiveSSL.com/ssl-certificate-support/cert_installation/UTN-USERFirst-Hardware.crt>`_ @@ -466,6 +717,25 @@ peer is supposed to furnish the other certificates necessary to chain from its certificate to a root certificate. See :rfc:`4158` for more discussion of the way in which certification chains can be built. +Combined key and certificate +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Often the private key is stored in the same file as the certificate; in this +case, only the ``certfile`` parameter to :meth:`SSLContext.load_cert_chain` +and :func:`wrap_socket` needs to be passed. If the private key is stored +with the certificate, it should come before the first certificate in +the certificate chain:: + + -----BEGIN RSA PRIVATE KEY----- + ... (private key in base64 encoding) ... + -----END RSA PRIVATE KEY----- + -----BEGIN CERTIFICATE----- + ... (certificate in base64 PEM encoding) ... + -----END CERTIFICATE----- + +Self-signed certificates +^^^^^^^^^^^^^^^^^^^^^^^^ + If you are going to create a server that provides SSL-encrypted connection services, you will need to acquire a certificate for that service. There are many ways of acquiring appropriate certificates, such as buying one from a @@ -519,101 +789,270 @@ should use the following idiom:: Client-side operation ^^^^^^^^^^^^^^^^^^^^^ -This example connects to an SSL server, prints the server's address and -certificate, sends some bytes, and reads part of the response:: +This example connects to an SSL server and prints the server's certificate:: import socket, ssl, pprint s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - # require a certificate from the server ssl_sock = ssl.wrap_socket(s, ca_certs="/etc/ca_certs_file", cert_reqs=ssl.CERT_REQUIRED) - ssl_sock.connect(('www.verisign.com', 443)) - print repr(ssl_sock.getpeername()) - print ssl_sock.cipher() - print pprint.pformat(ssl_sock.getpeercert()) - - # Set a simple HTTP request -- use httplib in actual code. - ssl_sock.write("""GET / HTTP/1.0\r - Host: www.verisign.com\r\n\r\n""") - - # Read a chunk of data. Will not necessarily - # read all the data returned by the server. - data = ssl_sock.read() - + pprint.pprint(ssl_sock.getpeercert()) # note that closing the SSLSocket will also close the underlying socket ssl_sock.close() -As of September 6, 2007, the certificate printed by this program looked like +As of January 6, 2012, the certificate printed by this program looks like this:: - {'notAfter': 'May 8 23:59:59 2009 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'),))} - -which is a fairly poorly-formed ``subject`` field. + {'issuer': ((('countryName', 'US'),), + (('organizationName', 'VeriSign, Inc.'),), + (('organizationalUnitName', 'VeriSign Trust Network'),), + (('organizationalUnitName', + 'Terms of use at https://www.verisign.com/rpa (c)06'),), + (('commonName', + 'VeriSign Class 3 Extended Validation SSL SGC CA'),)), + 'notAfter': 'May 25 23:59:59 2012 GMT', + 'notBefore': 'May 26 00:00:00 2010 GMT', + 'serialNumber': '53D2BEF924A7245E83CA01E46CAA2477', + 'subject': ((('1.3.6.1.4.1.311.60.2.1.3', 'US'),), + (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),), + (('businessCategory', 'V1.0, Clause 5.(b)'),), + (('serialNumber', '2497886'),), + (('countryName', 'US'),), + (('postalCode', '94043'),), + (('stateOrProvinceName', 'California'),), + (('localityName', 'Mountain View'),), + (('streetAddress', '487 East Middlefield Road'),), + (('organizationName', 'VeriSign, Inc.'),), + (('organizationalUnitName', ' Production Security Services'),), + (('commonName', 'www.verisign.com'),)), + 'subjectAltName': (('DNS', 'www.verisign.com'), + ('DNS', 'verisign.com'), + ('DNS', 'www.verisign.net'), + ('DNS', 'verisign.net'), + ('DNS', 'www.verisign.mobi'), + ('DNS', 'verisign.mobi'), + ('DNS', 'www.verisign.eu'), + ('DNS', 'verisign.eu')), + 'version': 3} + +This other example first creates an SSL context, instructs it to verify +certificates sent by peers, and feeds it a set of recognized certificate +authorities (CA):: + + >>> context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + >>> context.verify_mode = ssl.CERT_REQUIRED + >>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt") + +(it is assumed your operating system places a bundle of all CA certificates +in ``/etc/ssl/certs/ca-bundle.crt``; if not, you'll get an error and have +to adjust the location) + +When you use the context to connect to a server, :const:`CERT_REQUIRED` +validates the server certificate: it ensures that the server certificate +was signed with one of the CA certificates, and checks the signature for +correctness:: + + >>> conn = context.wrap_socket(socket.socket(socket.AF_INET)) + >>> conn.connect(("linuxfr.org", 443)) + +You should then fetch the certificate and check its fields for conformity:: + + >>> cert = conn.getpeercert() + >>> ssl.match_hostname(cert, "linuxfr.org") + +Visual inspection shows that the certificate does identify the desired service +(that is, the HTTPS host ``linuxfr.org``):: + + >>> pprint.pprint(cert) + {'issuer': ((('organizationName', 'CAcert Inc.'),), + (('organizationalUnitName', 'http://www.CAcert.org'),), + (('commonName', 'CAcert Class 3 Root'),)), + 'notAfter': 'Jun 7 21:02:24 2013 GMT', + 'notBefore': 'Jun 8 21:02:24 2011 GMT', + 'serialNumber': 'D3E9', + 'subject': ((('commonName', 'linuxfr.org'),),), + 'subjectAltName': (('DNS', 'linuxfr.org'), + ('othername', '<unsupported>'), + ('DNS', 'linuxfr.org'), + ('othername', '<unsupported>'), + ('DNS', 'dev.linuxfr.org'), + ('othername', '<unsupported>'), + ('DNS', 'prod.linuxfr.org'), + ('othername', '<unsupported>'), + ('DNS', 'alpha.linuxfr.org'), + ('othername', '<unsupported>'), + ('DNS', '*.linuxfr.org'), + ('othername', '<unsupported>')), + 'version': 3} + +Now that you are assured of its authenticity, you can proceed to talk with +the server:: + + >>> conn.sendall(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n") + >>> pprint.pprint(conn.recv(1024).split(b"\r\n")) + [b'HTTP/1.1 302 Found', + b'Date: Sun, 16 May 2010 13:43:28 GMT', + b'Server: Apache/2.2', + b'Location: https://linuxfr.org/pub/', + b'Vary: Accept-Encoding', + b'Connection: close', + b'Content-Type: text/html; charset=iso-8859-1', + b'', + b''] + +See the discussion of :ref:`ssl-security` below. + Server-side operation ^^^^^^^^^^^^^^^^^^^^^ -For server operation, typically you'd need to have a server certificate, and -private key, each in a file. You'd open a socket, bind it to a port, call -:meth:`listen` on it, then start waiting for clients to connect:: +For server operation, typically you'll need to have a server certificate, and +private key, each in a file. You'll first create a context holding the key +and the certificate, so that clients can check your authenticity. Then +you'll open a socket, bind it to a port, call :meth:`listen` on it, and start +waiting for clients to connect:: import socket, ssl + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + context.load_cert_chain(certfile="mycertfile", keyfile="mykeyfile") + bindsocket = socket.socket() bindsocket.bind(('myaddr.mydomain.com', 10023)) bindsocket.listen(5) -When one did, you'd call :meth:`accept` on the socket to get the new socket from -the other end, and use :func:`wrap_socket` to create a server-side SSL context -for it:: +When a client connects, you'll call :meth:`accept` on the socket to get the +new socket from the other end, and use the context's :meth:`SSLContext.wrap_socket` +method to create a server-side SSL socket for the connection:: while True: newsocket, fromaddr = bindsocket.accept() - connstream = ssl.wrap_socket(newsocket, - server_side=True, - certfile="mycertfile", - keyfile="mykeyfile", - ssl_version=ssl.PROTOCOL_TLSv1) + connstream = context.wrap_socket(newsocket, server_side=True) try: deal_with_client(connstream) finally: connstream.shutdown(socket.SHUT_RDWR) connstream.close() -Then you'd read data from the ``connstream`` and do something with it till you +Then you'll read data from the ``connstream`` and do something with it till you are finished with the client (or the client is finished with you):: def deal_with_client(connstream): - data = connstream.read() - # null data means the client is finished with us + data = connstream.recv(1024) + # empty data means the client is finished with us while data: if not do_something(connstream, data): # we'll assume do_something returns False # when we're finished with client break - data = connstream.read() + data = connstream.recv(1024) # finished with client -And go back to listening for new client connections. +And go back to listening for new client connections (of course, a real server +would probably handle each client connection in a separate thread, or put +the sockets in non-blocking mode and use an event loop). + + +.. _ssl-nonblocking: + +Notes on non-blocking sockets +----------------------------- + +When working with non-blocking sockets, there are several things you need +to be aware of: + +- Calling :func:`~select.select` tells you that the OS-level socket can be + read from (or written to), but it does not imply that there is sufficient + data at the upper SSL layer. For example, only part of an SSL frame might + have arrived. Therefore, you must be ready to handle :meth:`SSLSocket.recv` + and :meth:`SSLSocket.send` failures, and retry after another call to + :func:`~select.select`. + + (of course, similar provisions apply when using other primitives such as + :func:`~select.poll`) + +- The SSL handshake itself will be non-blocking: the + :meth:`SSLSocket.do_handshake` method has to be retried until it returns + successfully. Here is a synopsis using :func:`~select.select` to wait for + the socket's readiness:: + + while True: + try: + sock.do_handshake() + break + except ssl.SSLError as err: + if err.args[0] == ssl.SSL_ERROR_WANT_READ: + select.select([sock], [], []) + elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: + select.select([], [sock], []) + else: + raise + + +.. _ssl-security: + +Security considerations +----------------------- + +Verifying certificates +^^^^^^^^^^^^^^^^^^^^^^ + +:const:`CERT_NONE` is the default. Since it does not authenticate the other +peer, it can be insecure, especially in client mode where most of time you +would like to ensure the authenticity of the server you're talking to. +Therefore, when in client mode, it is highly recommended to use +:const:`CERT_REQUIRED`. However, it is in itself not sufficient; you also +have to check that the server certificate, which can be obtained by calling +:meth:`SSLSocket.getpeercert`, matches the desired service. For many +protocols and applications, the service can be identified by the hostname; +in this case, the :func:`match_hostname` function can be used. + +In server mode, if you want to authenticate your clients using the SSL layer +(rather than using a higher-level authentication mechanism), you'll also have +to specify :const:`CERT_REQUIRED` and similarly check the client certificate. + + .. note:: + + In client mode, :const:`CERT_OPTIONAL` and :const:`CERT_REQUIRED` are + equivalent unless anonymous ciphers are enabled (they are disabled + by default). + +Protocol versions +^^^^^^^^^^^^^^^^^ + +SSL version 2 is considered insecure and is therefore dangerous to use. If +you want maximum compatibility between clients and servers, it is recommended +to use :const:`PROTOCOL_SSLv23` as the protocol version and then disable +SSLv2 explicitly using the :data:`SSLContext.options` attribute:: + + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + context.options |= ssl.OP_NO_SSLv2 + +The SSL context created above will allow SSLv3 and TLSv1 connections, but +not SSLv2. + +Cipher selection +^^^^^^^^^^^^^^^^ + +If you have advanced security requirements, fine-tuning of the ciphers +enabled when negotiating a SSL session is possible through the +:meth:`SSLContext.set_ciphers` method. Starting from Python 3.2.3, the +ssl module disables certain weak ciphers by default, but you may want +to further restrict the cipher choice. For example:: + + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + context.set_ciphers('HIGH:!aNULL:!eNULL') + +The ``!aNULL:!eNULL`` part of the cipher spec is necessary to disable ciphers +which don't provide both encryption and authentication. Be sure to read +OpenSSL's documentation about the `cipher list +format <http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT>`_. +If you want to check which ciphers are enabled by a given cipher list, +use the ``openssl ciphers`` command on your system. .. seealso:: @@ -632,3 +1071,6 @@ And go back to listening for new client connections. `RFC 3280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile <http://www.ietf.org/rfc/rfc3280>`_ Housley et. al. + + `RFC 4366: Transport Layer Security (TLS) Extensions <http://www.ietf.org/rfc/rfc4366>`_ + Blake-Wilson et. al. |
