summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--OpenSSL/crypto/pkey.c5
-rw-r--r--OpenSSL/ssl/context.c58
-rw-r--r--OpenSSL/ssl/ssl.c14
-rw-r--r--OpenSSL/test/test_crypto.py14
-rw-r--r--OpenSSL/test/test_ssl.py104
-rw-r--r--doc/api/ssl.rst30
-rwxr-xr-xsetup.py22
8 files changed, 229 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index 6d1440f..a361ad4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2011-11-01 Jean-Paul Calderone <exarkun@twistedmatrix.com>
+
+ * OpenSSL/crypto/pkey.c: Raise TypeError when trying to check a
+ PKey instance which has no private component, instead of crashing.
+ Based on fix by <lp:~dataway>.
+
2011-09-14 Žiga Seilnacht <lp:ziga-seilnacht>
* OpenSSL/crypto/crypto.c: Allow exceptions from passphrase
diff --git a/OpenSSL/crypto/pkey.c b/OpenSSL/crypto/pkey.c
index 27ea4d4..b9472ec 100644
--- a/OpenSSL/crypto/pkey.c
+++ b/OpenSSL/crypto/pkey.c
@@ -124,6 +124,11 @@ crypto_PKey_check(crypto_PKeyObj *self, PyObject *args) {
return NULL;
}
+ if (self->only_public) {
+ PyErr_SetString(PyExc_TypeError, "public key only");
+ return NULL;
+ }
+
if (self->pkey->type == EVP_PKEY_RSA) {
RSA *rsa;
rsa = EVP_PKEY_get1_RSA(self->pkey);
diff --git a/OpenSSL/ssl/context.c b/OpenSSL/ssl/context.c
index b2d3431..0b9f4b6 100644
--- a/OpenSSL/ssl/context.c
+++ b/OpenSSL/ssl/context.c
@@ -690,8 +690,8 @@ ssl_Context_load_client_ca(ssl_ContextObj *self, PyObject *args)
}
static char ssl_Context_set_session_id_doc[] = "\n\
-Set the session identifier, this is needed if you want to do session\n\
-resumption (which, ironically, isn't implemented yet)\n\
+Set the session identifier. This is needed if you want to do session\n\
+resumption.\n\
\n\
:param buf: A Python object that can be safely converted to a string\n\
:returns: None\n\
@@ -717,6 +717,39 @@ ssl_Context_set_session_id(ssl_ContextObj *self, PyObject *args)
}
}
+static char ssl_Context_set_session_cache_mode_doc[] = "\n\
+Enable/disable session caching and specify the mode used.\n\
+\n\
+:param mode: One or more of the SESS_CACHE_* flags (combine using bitwise or)\n\
+:returns: The previously set caching mode.\n\
+";
+static PyObject *
+ssl_Context_set_session_cache_mode(ssl_ContextObj *self, PyObject *args) {
+ long mode, result;
+
+ if (!PyArg_ParseTuple(args, "l:set_session_cache_mode", &mode)) {
+ return NULL;
+ }
+
+ result = SSL_CTX_set_session_cache_mode(self->ctx, mode);
+ return PyLong_FromLong(result);
+
+}
+
+static char ssl_Context_get_session_cache_mode_doc[] = "\n\
+:returns: The currently used cache mode.\n\
+";
+static PyObject *
+ssl_Context_get_session_cache_mode(ssl_ContextObj *self, PyObject *args) {
+ long result;
+
+ if (!PyArg_ParseTuple(args, ":get_session_cache_mode")) {
+ return NULL;
+ }
+ result = SSL_CTX_get_session_cache_mode(self->ctx);
+ return PyLong_FromLong(result);
+}
+
static char ssl_Context_set_verify_doc[] = "\n\
Set the verify mode and verify callback\n\
\n\
@@ -984,24 +1017,6 @@ ssl_Context_set_timeout(ssl_ContextObj *self, PyObject *args)
return PyLong_FromLong(ret);
}
-static char ssl_Context_set_session_cache_mode_doc[] = "\n\
-Set session cache mode\n\
-\n\
-:param timeout: The mode as an integer\n\
-:return: The previous set cache mode\n\
-";
-static PyObject *
-ssl_Context_set_session_cache_mode(ssl_ContextObj *self, PyObject *args)
-{
- long t, ret;
-
- if (!PyArg_ParseTuple(args, "l:set_session_cache_mode", &t))
- return NULL;
-
- ret = SSL_CTX_set_session_cache_mode(self->ctx, t);
- return PyLong_FromLong(ret);
-}
-
static char ssl_Context_get_timeout_doc[] = "\n\
Get the session timeout\n\
\n\
@@ -1194,6 +1209,8 @@ static PyMethodDef ssl_Context_methods[] = {
ADD_METHOD(check_privatekey),
ADD_METHOD(load_client_ca),
ADD_METHOD(set_session_id),
+ ADD_METHOD(set_session_cache_mode),
+ ADD_METHOD(get_session_cache_mode),
ADD_METHOD(set_verify),
ADD_METHOD(set_verify_depth),
ADD_METHOD(get_verify_mode),
@@ -1204,7 +1221,6 @@ static PyMethodDef ssl_Context_methods[] = {
ADD_METHOD(add_client_ca),
ADD_METHOD(set_timeout),
ADD_METHOD(get_timeout),
- ADD_METHOD(set_session_cache_mode),
ADD_METHOD(set_info_callback),
ADD_METHOD(get_app_data),
ADD_METHOD(set_app_data),
diff --git a/OpenSSL/ssl/ssl.c b/OpenSSL/ssl/ssl.c
index cee3661..a68f447 100644
--- a/OpenSSL/ssl/ssl.c
+++ b/OpenSSL/ssl/ssl.c
@@ -274,6 +274,20 @@ do { \
PyModule_AddIntConstant(module, "SSLEAY_PLATFORM", SSLEAY_PLATFORM);
PyModule_AddIntConstant(module, "SSLEAY_DIR", SSLEAY_DIR);
+ /* Cache modes */
+#define CACHE_MODE(mode) \
+ PyModule_AddIntConstant(module, "SESS_CACHE_" #mode, SSL_SESS_CACHE_##mode)
+
+ CACHE_MODE(OFF);
+ CACHE_MODE(CLIENT);
+ CACHE_MODE(SERVER);
+ CACHE_MODE(BOTH);
+ CACHE_MODE(NO_AUTO_CLEAR);
+ CACHE_MODE(NO_INTERNAL_LOOKUP);
+ CACHE_MODE(NO_INTERNAL_STORE);
+ CACHE_MODE(NO_INTERNAL);
+#undef CACHE_MODE
+
/* Straight up version number */
PyModule_AddIntConstant(module, "OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER);
diff --git a/OpenSSL/test/test_crypto.py b/OpenSSL/test/test_crypto.py
index e0d7b27..62b9429 100644
--- a/OpenSSL/test/test_crypto.py
+++ b/OpenSSL/test/test_crypto.py
@@ -630,6 +630,20 @@ class PKeyTests(TestCase):
self.assertRaises(TypeError, PKey().check, 1)
+ def test_check_public_key(self):
+ """
+ :py:meth:`PKeyType.check` raises :py:exc:`TypeError` if only the public
+ part of the key is available.
+ """
+ # A trick to get a public-only key
+ key = PKey()
+ key.generate_key(TYPE_RSA, 512)
+ cert = X509()
+ cert.set_pubkey(key)
+ pub = cert.get_pubkey()
+ self.assertRaises(TypeError, pub.check)
+
+
class X509NameTests(TestCase):
"""
diff --git a/OpenSSL/test/test_ssl.py b/OpenSSL/test/test_ssl.py
index c9417b9..cda6d53 100644
--- a/OpenSSL/test/test_ssl.py
+++ b/OpenSSL/test/test_ssl.py
@@ -10,7 +10,7 @@ from errno import ECONNREFUSED, EINPROGRESS, EWOULDBLOCK
from sys import platform, version_info
from socket import error, socket
from os import makedirs
-from os.path import join
+from os.path import join, dirname
from unittest import main
from weakref import ref
@@ -28,6 +28,11 @@ from OpenSSL.SSL import (
VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE, VERIFY_NONE)
from OpenSSL.SSL import (
+ SESS_CACHE_OFF, SESS_CACHE_CLIENT, SESS_CACHE_SERVER, SESS_CACHE_BOTH,
+ SESS_CACHE_NO_AUTO_CLEAR, SESS_CACHE_NO_INTERNAL_LOOKUP,
+ SESS_CACHE_NO_INTERNAL_STORE, SESS_CACHE_NO_INTERNAL)
+
+from OpenSSL.SSL import (
Error, SysCallError, WantReadError, ZeroReturnError, SSLeay_version)
from OpenSSL.SSL import Context, ContextType, Connection, ConnectionType
@@ -909,6 +914,37 @@ class ContextTests(TestCase, _LoopbackMixin):
self.assertEquals(conn.get_cipher_list(), ["EXP-RC4-MD5"])
+ def test_set_session_cache_mode_wrong_args(self):
+ """
+ L{Context.set_session_cache_mode} raises L{TypeError} if called with
+ other than one integer argument.
+ """
+ context = Context(TLSv1_METHOD)
+ self.assertRaises(TypeError, context.set_session_cache_mode)
+ self.assertRaises(TypeError, context.set_session_cache_mode, object())
+
+
+ def test_get_session_cache_mode_wrong_args(self):
+ """
+ L{Context.get_session_cache_mode} raises L{TypeError} if called with any
+ arguments.
+ """
+ context = Context(TLSv1_METHOD)
+ self.assertRaises(TypeError, context.get_session_cache_mode, 1)
+
+
+ def test_session_cache_mode(self):
+ """
+ L{Context.set_session_cache_mode} specifies how sessions are cached.
+ The setting can be retrieved via L{Context.get_session_cache_mode}.
+ """
+ context = Context(TLSv1_METHOD)
+ old = context.set_session_cache_mode(SESS_CACHE_OFF)
+ off = context.set_session_cache_mode(SESS_CACHE_BOTH)
+ self.assertEqual(SESS_CACHE_OFF, off)
+ self.assertEqual(SESS_CACHE_BOTH, context.get_session_cache_mode())
+
+
class ServerNameCallbackTests(TestCase, _LoopbackMixin):
"""
@@ -1627,6 +1663,72 @@ class ConstantsTests(TestCase):
"OP_NO_COMPRESSION unavailable - OpenSSL version may be too old"
+ def test_sess_cache_off(self):
+ """
+ The value of L{OpenSSL.SSL.SESS_CACHE_OFF} 0x0, the value of
+ L{SSL_SESS_CACHE_OFF} defined by I{openssl/ssl.h}.
+ """
+ self.assertEqual(0x0, SESS_CACHE_OFF)
+
+
+ def test_sess_cache_client(self):
+ """
+ The value of L{OpenSSL.SSL.SESS_CACHE_CLIENT} 0x1, the value of
+ L{SSL_SESS_CACHE_CLIENT} defined by I{openssl/ssl.h}.
+ """
+ self.assertEqual(0x1, SESS_CACHE_CLIENT)
+
+
+ def test_sess_cache_server(self):
+ """
+ The value of L{OpenSSL.SSL.SESS_CACHE_SERVER} 0x2, the value of
+ L{SSL_SESS_CACHE_SERVER} defined by I{openssl/ssl.h}.
+ """
+ self.assertEqual(0x2, SESS_CACHE_SERVER)
+
+
+ def test_sess_cache_both(self):
+ """
+ The value of L{OpenSSL.SSL.SESS_CACHE_BOTH} 0x3, the value of
+ L{SSL_SESS_CACHE_BOTH} defined by I{openssl/ssl.h}.
+ """
+ self.assertEqual(0x3, SESS_CACHE_BOTH)
+
+
+ def test_sess_cache_no_auto_clear(self):
+ """
+ The value of L{OpenSSL.SSL.SESS_CACHE_NO_AUTO_CLEAR} 0x80, the value of
+ L{SSL_SESS_CACHE_NO_AUTO_CLEAR} defined by I{openssl/ssl.h}.
+ """
+ self.assertEqual(0x80, SESS_CACHE_NO_AUTO_CLEAR)
+
+
+ def test_sess_cache_no_internal_lookup(self):
+ """
+ The value of L{OpenSSL.SSL.SESS_CACHE_NO_INTERNAL_LOOKUP} 0x100, the
+ value of L{SSL_SESS_CACHE_NO_INTERNAL_LOOKUP} defined by
+ I{openssl/ssl.h}.
+ """
+ self.assertEqual(0x100, SESS_CACHE_NO_INTERNAL_LOOKUP)
+
+
+ def test_sess_cache_no_internal_store(self):
+ """
+ The value of L{OpenSSL.SSL.SESS_CACHE_NO_INTERNAL_STORE} 0x200, the
+ value of L{SSL_SESS_CACHE_NO_INTERNAL_STORE} defined by
+ I{openssl/ssl.h}.
+ """
+ self.assertEqual(0x200, SESS_CACHE_NO_INTERNAL_STORE)
+
+
+ def test_sess_cache_no_internal(self):
+ """
+ The value of L{OpenSSL.SSL.SESS_CACHE_NO_INTERNAL} 0x300, the value of
+ L{SSL_SESS_CACHE_NO_INTERNAL} defined by I{openssl/ssl.h}.
+ """
+ self.assertEqual(0x300, SESS_CACHE_NO_INTERNAL)
+
+
class MemoryBIOTests(TestCase, _LoopbackMixin):
"""
diff --git a/doc/api/ssl.rst b/doc/api/ssl.rst
index 1eed876..5014889 100644
--- a/doc/api/ssl.rst
+++ b/doc/api/ssl.rst
@@ -69,6 +69,20 @@ Context, Connection.
information to retrieve. See the man page for the :py:func:`SSLeay_version` C
API for details.
+.. py:data:: SESS_CACHE_OFF
+ SESS_CACHE_CLIENT
+ SESS_CACHE_SERVER
+ SESS_CACHE_BOTH
+ SESS_CACHE_NO_AUTO_CLEAR
+ SESS_CACHE_NO_INTERNAL_LOOKUP
+ SESS_CACHE_NO_INTERNAL_STORE
+ SESS_CACHE_NO_INTERNAL
+
+ Constants used with :py:meth:`Context.set_session_cache_mode` to specify
+ the behavior of the session cache and potential session reuse. See the man
+ page for the :py:func:`SSL_CTX_set_session_cache_mode` C API for details.
+
+ .. versionadded:: 0.14
.. py:data:: OPENSSL_VERSION_NUMBER
@@ -315,6 +329,22 @@ Context objects have the following methods:
*callback* should return a false value (e.g. an empty string).
+.. py:method:: Context.set_session_cache_mode(mode)
+
+ Set the behavior of the session cache used by all connections using this
+ Context. The previously set mode is returned. See :py:const:`SESS_CACHE_*`
+ for details about particular modes.
+
+ .. versionadded:: 0.14
+
+
+.. py:method:: Context.get_session_cache_mode()
+
+ Get the current session cache mode.
+
+ .. versionadded:: 0.14
+
+
.. py:method:: Context.set_session_id(name)
Set the context *name* within which a session can be reused for this
diff --git a/setup.py b/setup.py
index 2aa649e..8441274 100755
--- a/setup.py
+++ b/setup.py
@@ -218,5 +218,23 @@ High-level wrapper around a subset of the OpenSSL library, includes
sockets
* Callbacks written in Python
* Extensive error-handling mechanism, mirroring OpenSSL's error codes
-... and much more ;)"""
- )
+... and much more ;)""",
+ classifiers = [
+ 'Development Status :: 6 - Mature',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Apache Software License',
+ 'Operating System :: MacOS :: MacOS X',
+ 'Operating System :: Microsoft :: Windows',
+ 'Operating System :: POSIX',
+ 'Programming Language :: C',
+ 'Programming Language :: Python :: 2.4',
+ 'Programming Language :: Python :: 2.5',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3.2',
+ 'Programming Language :: Python :: Implementation :: CPython',
+ 'Programming Language :: Python :: Implementation :: PyPy',
+ 'Topic :: Security :: Cryptography',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ 'Topic :: System :: Networking',
+ ])