[pyOpenSSL] Re: [PATCH] Missing API for client authentication renegotiation

Frederic Peters fpeters at debian.org
Sun Dec 19 13:21:22 CET 2004


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;
 


More information about the pyopenssl-users mailing list