Commit 296a59d3 authored by Bill Janssen's avatar Bill Janssen

Add support for asyncore server-side SSL support. This requires

adding the 'makefile' method to ssl.SSLSocket, and importing the
requisite fakefile class from socket.py, and making the appropriate
changes to it to make it use the SSL connection.

Added sample HTTPS server to test_ssl.py, and test that uses it.

Change SSL tests to use https://svn.python.org/, instead of
www.sf.net and pop.gmail.com.

Added utility function to ssl module, get_server_certificate,
to wrap up the several things to be done to pull a certificate
from a remote server.
parent 7e84c7f4
...@@ -54,7 +54,7 @@ Functions, Constants, and Exceptions ...@@ -54,7 +54,7 @@ Functions, Constants, and Exceptions
network connection. This error is a subtype of :exc:`socket.error`, which network connection. This error is a subtype of :exc:`socket.error`, which
in turn is a subtype of :exc:`IOError`. in turn is a subtype of :exc:`IOError`.
.. function:: wrap_socket (sock [, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None]) .. function:: wrap_socket (sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None)
Takes an instance ``sock`` of :class:`socket.socket`, and returns an instance of :class:`ssl.SSLSocket`, a subtype Takes an instance ``sock`` of :class:`socket.socket`, and returns an instance of :class:`ssl.SSLSocket`, a subtype
of :class:`socket.socket`, which wraps the underlying socket in an SSL context. of :class:`socket.socket`, which wraps the underlying socket in an SSL context.
...@@ -162,6 +162,28 @@ Functions, Constants, and Exceptions ...@@ -162,6 +162,28 @@ Functions, Constants, and Exceptions
'Wed May 9 00:00:00 2007' 'Wed May 9 00:00:00 2007'
>>> >>>
.. 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 PEM-encoded string. If ``ssl_version`` is
specified, uses that version of the SSL protocol to attempt to
connect to the server. If ``ca_certs`` is specified, it should be
a file containing a list of root certificates, the same format as
used for the same parameter in :func:`wrap_socket`. The call 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)
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)
Given a certificate as an ASCII PEM string, returns a DER-encoded
sequence of bytes for that same certificate.
.. data:: CERT_NONE .. data:: CERT_NONE
Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` Value to pass to the ``cert_reqs`` parameter to :func:`sslobject`
...@@ -253,8 +275,12 @@ SSLSocket Objects ...@@ -253,8 +275,12 @@ SSLSocket Objects
If the ``binary_form`` parameter is :const:`True`, and a If the ``binary_form`` parameter is :const:`True`, and a
certificate was provided, this method returns the DER-encoded form certificate was provided, this method returns the DER-encoded form
of the entire certificate as a sequence of bytes. Note that this of the entire certificate as a sequence of bytes, or :const:`None` if the
binary certificate may not be valid. peer did not provide a certificate. This return
value is independent of validation; if validation was required
(:const:`CERT_OPTIONAL` or :const:`CERT_REQUIRED`), it will have
been validated, but if :const:`CERT_NONE` was used to establish the
connection, the certificate, if present, will not have been validated.
.. method:: SSLSocket.cipher() .. method:: SSLSocket.cipher()
...@@ -263,12 +289,6 @@ SSLSocket Objects ...@@ -263,12 +289,6 @@ SSLSocket Objects
number of secret bits being used. If no connection has been number of secret bits being used. If no connection has been
established, returns ``None``. established, returns ``None``.
.. method:: SSLSocket.ssl_shutdown()
Closes the SSL context (if any) over the socket, but leaves the socket connection
open for further use, if both sides are willing. This is different from :meth:`socket.socket.shutdown`,
which will close the connection, but leave the local socket available for further use.
.. index:: single: certificates .. index:: single: certificates
...@@ -351,6 +371,7 @@ authorities: ...@@ -351,6 +371,7 @@ authorities:
`CACert.org <http://www.cacert.org/index.php?id=3>`_, `CACert.org <http://www.cacert.org/index.php?id=3>`_,
`Thawte <http://www.thawte.com/roots/>`_, `Thawte <http://www.thawte.com/roots/>`_,
`Verisign <http://www.verisign.com/support/roots.html>`_, `Verisign <http://www.verisign.com/support/roots.html>`_,
`Positive SSL <http://www.PositiveSSL.com/ssl-certificate-support/cert_installation/UTN-USERFirst-Hardware.crt>`_ (used by python.org),
`Equifax and GeoTrust <http://www.geotrust.com/resources/root_certificates/index.asp>`_. `Equifax and GeoTrust <http://www.geotrust.com/resources/root_certificates/index.asp>`_.
In general, if you are using In general, if you are using
......
This diff is collapsed.
...@@ -113,7 +113,7 @@ class BasicTests(unittest.TestCase): ...@@ -113,7 +113,7 @@ class BasicTests(unittest.TestCase):
import os, httplib, ssl import os, httplib, ssl
with test_support.transient_internet(): with test_support.transient_internet():
s = socket.socket(socket.AF_INET) s = socket.socket(socket.AF_INET)
s.connect(("www.sf.net", 443)) s.connect(("svn.python.org", 443))
fd = s._sock.fileno() fd = s._sock.fileno()
sock = ssl.wrap_socket(s) sock = ssl.wrap_socket(s)
s = None s = None
......
This diff is collapsed.
...@@ -126,7 +126,6 @@ static int check_socket_and_wait_for_timeout(PySocketSockObject *s, ...@@ -126,7 +126,6 @@ static int check_socket_and_wait_for_timeout(PySocketSockObject *s,
int writing); int writing);
static PyObject *PySSL_peercert(PySSLObject *self, PyObject *args); static PyObject *PySSL_peercert(PySSLObject *self, PyObject *args);
static PyObject *PySSL_cipher(PySSLObject *self); static PyObject *PySSL_cipher(PySSLObject *self);
static PyObject *PySSL_SSLshutdown(PySSLObject *self);
#define PySSLObject_Check(v) (Py_Type(v) == &PySSL_Type) #define PySSLObject_Check(v) (Py_Type(v) == &PySSL_Type)
...@@ -661,7 +660,7 @@ _get_peer_alt_names (X509 *certificate) { ...@@ -661,7 +660,7 @@ _get_peer_alt_names (X509 *certificate) {
char buf[2048]; char buf[2048];
char *vptr; char *vptr;
int len; int len;
const unsigned char *p; unsigned char *p;
if (certificate == NULL) if (certificate == NULL)
return peer_alt_names; return peer_alt_names;
...@@ -1233,18 +1232,9 @@ static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) ...@@ -1233,18 +1232,9 @@ static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args)
Py_DECREF(buf); Py_DECREF(buf);
return NULL; return NULL;
} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
if (SSL_get_shutdown(self->ssl) != /* should contain a zero-length string */
SSL_RECEIVED_SHUTDOWN) _PyString_Resize(&buf, 0);
{ return buf;
Py_DECREF(buf);
PyErr_SetString(PySSLErrorObject,
"Socket closed without SSL shutdown handshake");
return NULL;
} else {
/* should contain a zero-length string */
_PyString_Resize(&buf, 0);
return buf;
}
} }
} }
do { do {
...@@ -1295,39 +1285,6 @@ PyDoc_STRVAR(PySSL_SSLread_doc, ...@@ -1295,39 +1285,6 @@ PyDoc_STRVAR(PySSL_SSLread_doc,
\n\ \n\
Read up to len bytes from the SSL socket."); Read up to len bytes from the SSL socket.");
static PyObject *PySSL_SSLshutdown(PySSLObject *self)
{
int err;
/* Guard against closed socket */
if (self->Socket->sock_fd < 0) {
PyErr_SetString(PySSLErrorObject,
"Underlying socket has been closed.");
return NULL;
}
PySSL_BEGIN_ALLOW_THREADS
err = SSL_shutdown(self->ssl);
if (err == 0) {
/* we need to call it again to finish the shutdown */
err = SSL_shutdown(self->ssl);
}
PySSL_END_ALLOW_THREADS
if (err < 0)
return PySSL_SetError(self, err, __FILE__, __LINE__);
else {
Py_INCREF(self->Socket);
return (PyObject *) (self->Socket);
}
}
PyDoc_STRVAR(PySSL_SSLshutdown_doc,
"shutdown(s) -> socket\n\
\n\
Does the SSL shutdown handshake with the remote end, and returns\n\
the underlying socket object.");
static PyMethodDef PySSLMethods[] = { static PyMethodDef PySSLMethods[] = {
{"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS, {"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS,
PySSL_SSLwrite_doc}, PySSL_SSLwrite_doc},
...@@ -1338,8 +1295,6 @@ static PyMethodDef PySSLMethods[] = { ...@@ -1338,8 +1295,6 @@ static PyMethodDef PySSLMethods[] = {
{"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS, {"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS,
PySSL_peercert_doc}, PySSL_peercert_doc},
{"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS}, {"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS},
{"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS,
PySSL_SSLshutdown_doc},
{NULL, NULL} {NULL, NULL}
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment