summaryrefslogtreecommitdiffstats
path: root/Doc
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2010-05-16 18:19:27 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2010-05-16 18:19:27 (GMT)
commit152efa2ae2532d29b03d449f245b2bd6895d3fcb (patch)
tree3b24bb8216fdfd546b064da73223ef334a574de6 /Doc
parent8eac60d9af6eea5f53a589eddc5f7efbf86385ba (diff)
downloadcpython-152efa2ae2532d29b03d449f245b2bd6895d3fcb.zip
cpython-152efa2ae2532d29b03d449f245b2bd6895d3fcb.tar.gz
cpython-152efa2ae2532d29b03d449f245b2bd6895d3fcb.tar.bz2
Issue #8550: Add first class `SSLContext` objects to the ssl module.
Diffstat (limited to 'Doc')
-rw-r--r--Doc/library/ssl.rst283
1 files changed, 236 insertions, 47 deletions
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
index 95f5f70..45ffcb0 100644
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -36,6 +36,11 @@ additional :meth:`read` and :meth:`write` methods, along with a method,
connection, and a method, :meth:`cipher`, to retrieve 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
------------------------------------
@@ -64,19 +69,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.
@@ -208,24 +200,36 @@ Functions, Constants, and Exceptions
.. 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
@@ -284,8 +288,8 @@ Functions, Constants, and Exceptions
.. versionadded:: 3.2
-SSLSocket Objects
------------------
+SSL Sockets
+-----------
.. method:: SSLSocket.read(nbytes=1024, buffer=None)
@@ -371,6 +375,83 @@ SSLSocket Objects
returned socket should always be used for further communication with the
other side of the connection, rather than the original socket.
+
+SSL Contexts
+------------
+
+.. class:: SSLContext(protocol)
+
+ An object holding various data longer-lived than single SSL connections,
+ such as SSL configuration options, certificate(s) and private key(s).
+ 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_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)
+
+ 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.
+
+.. 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
.. index:: single: X509 certificate
@@ -416,6 +497,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,
@@ -439,6 +523,9 @@ 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
@@ -458,6 +545,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
@@ -530,8 +636,7 @@ certificate, sends some bytes, and reads part of the response::
print(pprint.pformat(ssl_sock.getpeercert()))
# Set a simple HTTP request -- use http.client in actual code.
- ssl_sock.write("""GET / HTTP/1.0\r
- Host: www.verisign.com\r\n\r\n""")
+ ssl_sock.write(b"GET / HTTP/1.0\r\nHost: www.verisign.com\r\n\r\n")
# Read a chunk of data. Will not necessarily
# read all the data returned by the server.
@@ -561,39 +666,91 @@ this::
which is a fairly poorly-formed ``subject`` field.
+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_OPTIONAL
+ >>> 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_OPTIONAL`
+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.
+Here, the ``commonName`` field in the ``subject`` matches the desired HTTPS
+host ``linuxfr.org``::
+
+ >>> pprint.pprint(conn.getpeercert())
+ {'notAfter': 'Jun 26 21:41:46 2011 GMT',
+ 'subject': ((('commonName', 'linuxfr.org'),),),
+ 'subjectAltName': (('DNS', 'linuxfr.org'), ('othername', '<unsupported>'))}
+
+Now that you are assured of its authenticity, you can proceed to talk with
+the server::
+
+ >>> conn.write(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n")
+ 38
+ >>> pprint.pprint(conn.read().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)
- deal_with_client(connstream)
-
-Then you'd read data from the ``connstream`` and do something with it till you
+ connstream = context.wrap_socket(newsocket, server_side=True)
+ try:
+ deal_with_client(connstream)
+ finally:
+ connstream.close()
+
+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
+ # empty data means the client is finished with us
while data:
if not do_something(connstream, data):
# we'll assume do_something returns False
@@ -601,9 +758,41 @@ are finished with the client (or the client is finished with you)::
break
data = connstream.read()
# finished with client
- connstream.close()
-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-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 (obtained with
+:meth:`SSLSocket.getpeercert`) matches the desired service. The exact way
+of doing so depends on the higher-level protocol used; for example, with
+HTTPS, you'll check that the host name in the URL matches either the
+``commonName`` field in the ``subjectName``, or one of the ``DNS`` fields
+in the ``subjectAltName``.
+
+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).
.. seealso::