From eraviart at entrouvert.com Sun Dec 19 09:54:23 2004
From: eraviart at entrouvert.com (Emmanuel Raviart)
Date: Sun, 19 Dec 2004 09:54:23 +0100
Subject: [pyOpenSSL] Missing API for client authentication renegotiation
Message-ID: <41C541BF.1080602@entrouvert.com>
Hello,
I'm using PyOpenSSL to develop a free software implementation of Liberty
Alliance single sign-on protocol.
http://lasso.entrouvert.org/souk
It works very well, but to improve client authentication, I need to
renegotiate client verify mode after the SSL connection is established.
So, I would like to transpose the following C code into Python:
SSL_set_verify(ssl,SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0);
/* Stop the client from just resuming the
un-authenticated session */
SSL_set_session_id_context(ssl,
(void *)&s_server_auth_session_id_context,
sizeof(s_server_auth_session_id_context));
SSL_renegotiate(ssl);
SSL_do_handshake(ssl);
ssl->state=SSL_ST_ACCEPT;
SSL_do_handshake(ssl);
[This code fragment is taken from wserver2.c sample code by Eric
Rescoria ]
But I didn't find in PyOpenSSL a way to:
- call SSL_set_verify
- change ssl->state without using SSL_set_accept_state
Is this a missing feature of PyOpenSSL? Is there another way to
implement client authentication renegotiation?
Regards,
Emmanuel Raviart
--
Lasso (Liberty Alliance Single Sign-On) -- http://lasso.entrouvert.org
Entr'ouvert -- www.entrouvert.com
From fpeters at debian.org Sun Dec 19 13:21:22 2004
From: fpeters at debian.org (Frederic Peters)
Date: Sun, 19 Dec 2004 13:21:22 +0100
Subject: [pyOpenSSL] Re: [PATCH] Missing API for client authentication renegotiation
In-Reply-To: <41C541BF.1080602@entrouvert.com>
References: <41C541BF.1080602@entrouvert.com>
Message-ID: <20041219122121.GA8792@entrouvert.com>
Emmanuel Raviart wrote:
> So, I would like to transpose the following C code into Python:
> SSL_set_verify(ssl,SSL_VERIFY_PEER |
> SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0);
>
> /* Stop the client from just resuming the
> un-authenticated session */
> SSL_set_session_id_context(ssl,
> (void *)&s_server_auth_session_id_context,
> sizeof(s_server_auth_session_id_context));
>
> SSL_renegotiate(ssl);
> SSL_do_handshake(ssl);
> ssl->state=SSL_ST_ACCEPT;
> SSL_do_handshake(ssl);
I wrote a patch for this; it adds bindings for SSL_set_verify,
SSL_set_verify_depth, SSL_get_verify_mode, SSL_get_verify_depth
and SSL_set_session_id_context. It also adds to new methods,
set_state and get_state to SSL objects and the SSL state constants
(SSL_ST_*).
It has *not* been extensively tested and I'm not sure at all wrt
the global_verify_callback function I copied/pasted from context.c
What are the odds for this to be included in pyOpenSSL ?
Regards,
Frederic
-------------- next part --------------
--- pyopenssl-0.6.orig/src/ssl/ssl.c
+++ pyopenssl-0.6/src/ssl/ssl.c
@@ -161,6 +161,15 @@
PyModule_AddIntConstant(module, "OP_NO_SSLv3", SSL_OP_NO_SSLv3);
PyModule_AddIntConstant(module, "OP_NO_TLSv1", SSL_OP_NO_TLSv1);
+ /* SSL state constants */
+ PyModule_AddIntConstant(module, "ST_CONNECT", SSL_ST_CONNECT);
+ PyModule_AddIntConstant(module, "ST_ACCEPT", SSL_ST_ACCEPT);
+ PyModule_AddIntConstant(module, "ST_MASK", SSL_ST_MASK);
+ PyModule_AddIntConstant(module, "ST_INIT", SSL_ST_INIT);
+ PyModule_AddIntConstant(module, "ST_BEFORE", SSL_ST_BEFORE);
+ PyModule_AddIntConstant(module, "ST_OK", SSL_ST_OK);
+ PyModule_AddIntConstant(module, "ST_RENEGOTIATE", SSL_ST_RENEGOTIATE);
+
/* More SSL option constants */
PyModule_AddIntConstant(module, "OP_MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG);
PyModule_AddIntConstant(module, "OP_NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG);
--- pyopenssl-0.6.orig/src/ssl/connection.c
+++ pyopenssl-0.6/src/ssl/connection.c
@@ -199,6 +199,64 @@
}
/*
+ * Globally defined verify callback
+ *
+ * Arguments: ok - True everything is OK "so far", false otherwise
+ * x509_ctx - Contains the certificate being checked, the current
+ * error number and depth, and the Connection we're
+ * dealing with
+ * Returns: True if everything is okay, false otherwise
+ */
+static int
+global_verify_callback(int ok, X509_STORE_CTX *x509_ctx)
+{
+ PyObject *argv, *ret;
+ SSL *ssl;
+ ssl_ConnectionObj *conn;
+ crypto_X509Obj *cert;
+ int errnum, errdepth, c_ret;
+
+ cert = crypto_X509_New(X509_STORE_CTX_get_current_cert(x509_ctx), 0);
+ errnum = X509_STORE_CTX_get_error(x509_ctx);
+ errdepth = X509_STORE_CTX_get_error_depth(x509_ctx);
+ ssl = (SSL *)X509_STORE_CTX_get_app_data(x509_ctx);
+ conn = (ssl_ConnectionObj *)SSL_get_app_data(ssl);
+
+ argv = Py_BuildValue("(OOiii)", (PyObject *)conn, (PyObject *)cert,
+ errnum, errdepth, ok);
+ Py_DECREF(cert);
+ if (conn->tstate != NULL)
+ {
+ /* We need to get back our thread state before calling the callback */
+ MY_END_ALLOW_THREADS(conn->tstate);
+ ret = PyEval_CallObject(conn->context->verify_callback, argv);
+ MY_BEGIN_ALLOW_THREADS(conn->tstate);
+ }
+ else
+ {
+ ret = PyEval_CallObject(conn->context->verify_callback, argv);
+ }
+ Py_DECREF(argv);
+
+ if (ret == NULL)
+ return 0;
+
+ if (PyObject_IsTrue(ret))
+ {
+ X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
+ c_ret = 1;
+ }
+ else
+ c_ret = 0;
+
+ Py_DECREF(ret);
+
+ return c_ret;
+}
+
+
+
+/*
* Here be member methods of the Connection "class"
*/
@@ -853,6 +911,169 @@
return PyInt_FromLong((long)SSL_want_write(self->ssl));
}
+static char ssl_Connection_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\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be:\n\
+ buf - A Python object that can be safely converted to a string\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Connection_set_session_id(ssl_ConnectionObj *self, PyObject *args)
+{
+ char *buf;
+ int len;
+
+ if (!PyArg_ParseTuple(args, "s#:set_session_id", &buf, &len))
+ return NULL;
+
+ if (!SSL_set_session_id_context(self->ssl, buf, len))
+ {
+ exception_from_error_queue();
+ return NULL;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static char ssl_Connection_set_verify_doc[] = "\n\
+Set the verify mode and verify callback\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be:\n\
+ mode - The verify mode, this is either SSL_VERIFY_NONE or\n\
+ SSL_VERIFY_PEER combined with possible other flags\n\
+ callback - The Python callback to use\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Connection_set_verify(ssl_ConnectionObj *self, PyObject *args)
+{
+ int mode;
+ PyObject *callback = NULL;
+
+ if (!PyArg_ParseTuple(args, "iO:set_verify", &mode, &callback))
+ return NULL;
+
+ if (!PyCallable_Check(callback))
+ {
+ PyErr_SetString(PyExc_TypeError, "expected PyCallable");
+ return NULL;
+ }
+
+ Py_DECREF(self->verify_callback);
+ Py_INCREF(callback);
+ self->verify_callback = callback;
+ SSL_set_verify(self->ssl, mode, global_verify_callback);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Connection_set_verify_depth_doc[] = "\n\
+Set the verify depth\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be:\n\
+ depth - An integer specifying the verify depth\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Connection_set_verify_depth(ssl_ConnectionObj *self, PyObject *args)
+{
+ int depth;
+
+ if (!PyArg_ParseTuple(args, "i:set_verify_depth", &depth))
+ return NULL;
+
+ SSL_set_verify_depth(self->ssl, depth);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char ssl_Connection_get_verify_mode_doc[] = "\n\
+Get the verify mode\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The verify mode\n\
+";
+static PyObject *
+ssl_Connection_get_verify_mode(ssl_ConnectionObj *self, PyObject *args)
+{
+ int mode;
+
+ if (!PyArg_ParseTuple(args, ":get_verify_mode"))
+ return NULL;
+
+ mode = SSL_get_verify_mode(self->ssl);
+ return PyInt_FromLong((long)mode);
+}
+
+static char ssl_Connection_get_verify_depth_doc[] = "\n\
+Get the verify depth\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The verify depth\n\
+";
+static PyObject *
+ssl_Connection_get_verify_depth(ssl_ConnectionObj *self, PyObject *args)
+{
+ int depth;
+
+ if (!PyArg_ParseTuple(args, ":get_verify_depth"))
+ return NULL;
+
+ depth = SSL_get_verify_depth(self->ssl);
+ return PyInt_FromLong((long)depth);
+}
+
+
+static char ssl_Connection_get_state_doc[] = "\n\
+Get application data\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The SSL state\n\
+";
+static PyObject *
+ssl_Connection_get_state(ssl_ConnectionObj *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":get_state"))
+ return NULL;
+
+ return PyInt_FromLong(self->ssl->state);
+}
+
+static char ssl_Connection_set_state_doc[] = "\n\
+Set application data\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be\n\
+ state - The SSL state\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Connection_set_state(ssl_ConnectionObj *self, PyObject *args)
+{
+ int state;
+
+ if (!PyArg_ParseTuple(args, "i:set_state", &state))
+ return NULL;
+
+ self->ssl->state = state;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
/*
* Member methods in the Connection object
* ADD_METHOD(name) expands to a correct PyMethodDef declaration
@@ -895,12 +1116,18 @@
ADD_METHOD(want_write),
ADD_METHOD(set_accept_state),
ADD_METHOD(set_connect_state),
+ ADD_METHOD(set_session_id),
+ ADD_METHOD(set_verify),
+ ADD_METHOD(set_verify_depth),
+ ADD_METHOD(get_verify_mode),
+ ADD_METHOD(get_verify_depth),
+ ADD_METHOD(get_state),
+ ADD_METHOD(set_state),
{ NULL, NULL }
};
#undef ADD_ALIAS
#undef ADD_METHOD
-
/*
* Constructor for Connection objects
*
@@ -928,6 +1155,8 @@
Py_INCREF(Py_None);
self->app_data = Py_None;
+ Py_INCREF(Py_None);
+ self->verify_callback = Py_None;
self->tstate = NULL;
--- pyopenssl-0.6.orig/src/ssl/connection.h
+++ pyopenssl-0.6/src/ssl/connection.h
@@ -43,6 +43,7 @@
ssl_ContextObj *context;
PyObject *socket;
PyThreadState *tstate;
+ PyObject *verify_callback;
PyObject *app_data;
} ssl_ConnectionObj;
From niklas at registrar.no Mon Dec 20 15:05:43 2004
From: niklas at registrar.no (Niklas Saers)
Date: Mon, 20 Dec 2004 15:05:43 +0100
Subject: [pyOpenSSL] setting the key password
Message-ID: <41C6DC37.7090706@registrar.no>
Hi everyone,
I'm using SecureXMLRPCServer to do my XMLRPC communication via SSL. For
this I have a server.pkey and a server.cert, and when running the
application I get: "Enter PEM pass phrase:" I want this to be a daemon
that runs on a server and starts thus I would like to set the password
without keyboard interaction. I've been unsuccessful at piping the
password in, and I was wondering if I could set a variable or if there
are other options available to me?
Sincerely yours
Niklas Saers
From jos at xos.nl Mon Dec 20 16:23:11 2004
From: jos at xos.nl (Jos Vos)
Date: Mon, 20 Dec 2004 16:23:11 +0100
Subject: [pyOpenSSL] setting the key password
In-Reply-To: <41C6DC37.7090706@registrar.no>; from niklas@registrar.no on Mon, Dec 20, 2004 at 03:05:43PM +0100
References: <41C6DC37.7090706@registrar.no>
Message-ID: <20041220162311.A22228@xos037.xos.nl>
On Mon, Dec 20, 2004 at 03:05:43PM +0100, Niklas Saers wrote:
> I'm using SecureXMLRPCServer to do my XMLRPC communication via SSL. For
> this I have a server.pkey and a server.cert, and when running the
> application I get: "Enter PEM pass phrase:" I want this to be a daemon
> that runs on a server and starts thus I would like to set the password
> without keyboard interaction. I've been unsuccessful at piping the
> password in, and I was wondering if I could set a variable or if there
> are other options available to me?
You have to change the private key part for that, as follows:
openssl rsa -in server.pkey -out server2.pkey
And then use server2.pkey i.s.o. server.pkey from now on.
--
-- Jos Vos
-- X/OS Experts in Open Systems BV | Phone: +31 20 6938364
-- Amsterdam, The Netherlands | Fax: +31 20 6948204