[Python-Dev] Other SSL issues in the tracker have been marked

Bill Janssen janssen at parc.com
Mon Aug 27 20:09:41 CEST 2007


> Some of the code sets the error string in this directly before
> returning NULL, and other pieces of the code call PySSL_SetError,
> which creates the error string.  I think some of the places which set
> the string directly probably shouldn't; instead, they should call
> PySSL_SetError to cons up the error name directly from the err code.
> However, PySSL_SetError only works after the construction of an ssl
> object, which means it can't be used there...  I'll take a longer look
> at it and see if there's a reasonable fix.

Here's a patch which addresses this.  It also fixes the indentation in
PySSL_SetError, bringing it into line with PEP 7, fixes a compile warning
about one of the OpenSSL macros, and makes the namespace a bit more
consistent.  I've tested it on FC 7 and OS X 10.4.

% ./python ./Lib/test/regrtest.py -R :1: -u all test_ssl
test_ssl
beginning 6 repetitions
123456
......
1 test OK.
[29244 refs]
%

Bill


Index: Modules/_ssl.c
===================================================================
--- Modules/_ssl.c	(revision 57564)
+++ Modules/_ssl.c	(working copy)
@@ -122,71 +122,74 @@
 	char buf[2048];
 	char *errstr;
 	int err;
-	enum py_ssl_error p;
+	enum py_ssl_error p = PY_SSL_ERROR_NONE;
 
 	assert(ret <= 0);
 
-	err = SSL_get_error(obj->ssl, ret);
+	if ((obj != NULL) && (obj->ssl != NULL)) {
+		err = SSL_get_error(obj->ssl, ret);
 
-	switch (err) {
-	case SSL_ERROR_ZERO_RETURN:
-		errstr = "TLS/SSL connection has been closed";
-		p = PY_SSL_ERROR_ZERO_RETURN;
-		break;
-	case SSL_ERROR_WANT_READ:
-		errstr = "The operation did not complete (read)";
-		p = PY_SSL_ERROR_WANT_READ;
-		break;
-	case SSL_ERROR_WANT_WRITE:
-		p = PY_SSL_ERROR_WANT_WRITE;
-		errstr = "The operation did not complete (write)";
-		break;
-	case SSL_ERROR_WANT_X509_LOOKUP:
-		p = PY_SSL_ERROR_WANT_X509_LOOKUP;
-		errstr = "The operation did not complete (X509 lookup)";
-		break;
-	case SSL_ERROR_WANT_CONNECT:
-		p = PY_SSL_ERROR_WANT_CONNECT;
-		errstr = "The operation did not complete (connect)";
-		break;
-	case SSL_ERROR_SYSCALL:
-	{
-		unsigned long e = ERR_get_error();
-		if (e == 0) {
-			if (ret == 0 || !obj->Socket) {
-				p = PY_SSL_ERROR_EOF;
-				errstr = "EOF occurred in violation of protocol";
-			} else if (ret == -1) {
-				/* the underlying BIO reported an I/O error */
-				return obj->Socket->errorhandler();
-			} else {  /* possible? */
+		switch (err) {
+		case SSL_ERROR_ZERO_RETURN:
+			errstr = "TLS/SSL connection has been closed";
+			p = PY_SSL_ERROR_ZERO_RETURN;
+			break;
+		case SSL_ERROR_WANT_READ:
+			errstr = "The operation did not complete (read)";
+			p = PY_SSL_ERROR_WANT_READ;
+			break;
+		case SSL_ERROR_WANT_WRITE:
+			p = PY_SSL_ERROR_WANT_WRITE;
+			errstr = "The operation did not complete (write)";
+			break;
+		case SSL_ERROR_WANT_X509_LOOKUP:
+			p = PY_SSL_ERROR_WANT_X509_LOOKUP;
+			errstr = "The operation did not complete (X509 lookup)";
+			break;
+		case SSL_ERROR_WANT_CONNECT:
+			p = PY_SSL_ERROR_WANT_CONNECT;
+			errstr = "The operation did not complete (connect)";
+			break;
+		case SSL_ERROR_SYSCALL:
+		{
+			unsigned long e = ERR_get_error();
+			if (e == 0) {
+				if (ret == 0 || !obj->Socket) {
+					p = PY_SSL_ERROR_EOF;
+					errstr = "EOF occurred in violation of protocol";
+				} else if (ret == -1) {
+					/* the underlying BIO reported an I/O error */
+					return obj->Socket->errorhandler();
+				} else { /* possible? */
+					p = PY_SSL_ERROR_SYSCALL;
+					errstr = "Some I/O error occurred";
+				}
+			} else {
 				p = PY_SSL_ERROR_SYSCALL;
-				errstr = "Some I/O error occurred";
+				/* XXX Protected by global interpreter lock */
+				errstr = ERR_error_string(e, NULL);
 			}
-		} else {
-			p = PY_SSL_ERROR_SYSCALL;
-			/* XXX Protected by global interpreter lock */
-			errstr = ERR_error_string(e, NULL);
+			break;
 		}
-		break;
-	}
-	case SSL_ERROR_SSL:
-	{
-		unsigned long e = ERR_get_error();
-		p = PY_SSL_ERROR_SSL;
-		if (e != 0)
-			/* XXX Protected by global interpreter lock */
-			errstr = ERR_error_string(e, NULL);
-		else { /* possible? */
-			errstr = "A failure in the SSL library occurred";
+		case SSL_ERROR_SSL:
+		{
+			unsigned long e = ERR_get_error();
+			p = PY_SSL_ERROR_SSL;
+			if (e != 0)
+				/* XXX Protected by global interpreter lock */
+				errstr = ERR_error_string(e, NULL);
+			else {	/* possible? */
+				errstr = "A failure in the SSL library occurred";
+			}
+			break;
 		}
-		break;
+		default:
+			p = PY_SSL_ERROR_INVALID_ERROR_CODE;
+			errstr = "Invalid error code";
+		}
+	} else {
+		errstr = ERR_error_string(ERR_peek_last_error(), NULL);
 	}
-	default:
-		p = PY_SSL_ERROR_INVALID_ERROR_CODE;
-		errstr = "Invalid error code";
-	}
-
 	PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr);
 	v = Py_BuildValue("(is)", p, buf);
 	if (v != NULL) {
@@ -256,8 +259,8 @@
 			ret = SSL_CTX_load_verify_locations(self->ctx,
 							    cacerts_file, NULL);
 			Py_END_ALLOW_THREADS
-			if (ret < 1) {
-				errstr = ERRSTR("SSL_CTX_load_verify_locations");
+			if (ret != 1) {
+				PySSL_SetError(NULL, 0, __FILE__, __LINE__);
 				goto fail;
 			}
 		}
@@ -267,8 +270,8 @@
 		ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file,
 						  SSL_FILETYPE_PEM);
 		Py_END_ALLOW_THREADS
-		if (ret < 1) {
-			errstr = ERRSTR("SSL_CTX_use_PrivateKey_file error");
+		if (ret != 1) {
+			PySSL_SetError(NULL, 0, __FILE__, __LINE__);
 			goto fail;
 		}
 
@@ -276,8 +279,8 @@
 		ret = SSL_CTX_use_certificate_chain_file(self->ctx,
 						       cert_file);
 		Py_END_ALLOW_THREADS
-		if (ret < 1) {
-			errstr = ERRSTR("SSL_CTX_use_certificate_chain_file error") ;
+		if (ret != 1) {
+			PySSL_SetError(NULL, 0, __FILE__, __LINE__);
 			goto fail;
 		}
 		SSL_CTX_set_options(self->ctx, SSL_OP_ALL); /* ssl compatibility */
@@ -375,7 +378,7 @@
 }
 
 static PyObject *
-PySocket_ssl(PyObject *self, PyObject *args)
+PySSL_sslwrap(PyObject *self, PyObject *args)
 {
 	PySocketSockObject *Sock;
 	int server_side = 0;
@@ -431,6 +434,9 @@
 	PyObject *pd = PyDict_New();
 	int index_counter;
 
+	if (pd == NULL)
+		return NULL;
+
 	for (index_counter = 0;
 	     index_counter < X509_NAME_entry_count(xname);
 	     index_counter++)
@@ -548,7 +554,7 @@
 	}
 	Py_DECREF(pnotBefore);
 
-	BIO_reset(biobuf);
+	(void) BIO_reset(biobuf);
 	notAfter = X509_get_notAfter(self->peer_cert);
 	ASN1_TIME_print(biobuf, notAfter);
 	len = BIO_gets(biobuf, buf, sizeof(buf)-1);
@@ -857,7 +863,7 @@
 
 static PyTypeObject PySSL_Type = {
 	PyVarObject_HEAD_INIT(NULL, 0)
-	"socket.SSL",			/*tp_name*/
+	"ssl.SSLContext",		/*tp_name*/
 	sizeof(PySSLObject),		/*tp_basicsize*/
 	0,				/*tp_itemsize*/
 	/* methods */
@@ -932,7 +938,7 @@
 "RAND_egd(path) -> bytes\n\
 \n\
 Queries the entropy gather daemon (EGD) on socket path.  Returns number\n\
-of bytes read.  Raises socket.sslerror if connection to EGD fails or\n\
+of bytes read.  Raises ssl.sslerror if connection to EGD fails or\n\
 if it does provide enough data to seed PRNG.");
 
 #endif
@@ -940,7 +946,7 @@
 /* List of functions exported by this module. */
 
 static PyMethodDef PySSL_methods[] = {
-	{"sslwrap",             PySocket_ssl,
+	{"sslwrap",             PySSL_sslwrap,
          METH_VARARGS, ssl_doc},
 #ifdef HAVE_OPENSSL_RAND
 	{"RAND_add",            PySSL_RAND_add, METH_VARARGS,
@@ -979,7 +985,7 @@
 	SSLeay_add_ssl_algorithms();
 
 	/* Add symbols to module dict */
-	PySSLErrorObject = PyErr_NewException("socket.sslerror",
+	PySSLErrorObject = PyErr_NewException("ssl.sslerror",
 					      PySocketModule.error,
 					      NULL);
 	if (PySSLErrorObject == NULL)



More information about the Python-Dev mailing list