static PyObject *PySSL_SSLshutdown(PySSLObject *self) { int err; PySocketSockObject *sock = (PySocketSockObject *) PyWeakref_GetObject(self->Socket); /* Guard against closed socket */ if ((((PyObject*)sock) == Py_None) || (sock->sock_fd < 0)) { _setSSLError("Underlying socket connection gone", PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); 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(sock); return (PyObject *) sock; } }
static PyObject *PySSL_SSLpending(PySSLObject *self) { int count = 0; PySSL_BEGIN_ALLOW_THREADS count = SSL_pending(self->ssl); PySSL_END_ALLOW_THREADS if (count < 0) return PySSL_SetError(self, count, __FILE__, __LINE__); else return PyLong_FromLong(count); }
static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) { char *data; int len; int count; int sockstate; int err; if (!PyArg_ParseTuple(args, "s#:write", &data, &count)) return NULL; sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The write operation timed out"); return NULL; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); return NULL; } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { PyErr_SetString(PySSLErrorObject, "Underlying socket too large for select()."); return NULL; } do { err = 0; Py_BEGIN_ALLOW_THREADS len = SSL_write(self->ssl, data, count); err = SSL_get_error(self->ssl, len); Py_END_ALLOW_THREADS if(PyErr_CheckSignals()) { return NULL; } if (err == SSL_ERROR_WANT_READ) { sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); } else if (err == SSL_ERROR_WANT_WRITE) { sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); } else { sockstate = SOCKET_OPERATION_OK; } if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The write operation timed out"); return NULL; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); return NULL; } else if (sockstate == SOCKET_IS_NONBLOCKING) { break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (len > 0) return PyInt_FromLong(len); else return PySSL_SetError(self, len); }
static PyObject * PySSL_peercert(PySSLObject *self, PyObject *args) { PyObject *retval = NULL; int len; int verification; PyObject *binary_mode = Py_None; if (!PyArg_ParseTuple(args, "|O:peer_certificate", &binary_mode)) return NULL; if (!self->peer_cert) Py_RETURN_NONE; if (PyObject_IsTrue(binary_mode)) { /* return cert in DER-encoded format */ unsigned char *bytes_buf = NULL; bytes_buf = NULL; len = i2d_X509(self->peer_cert, &bytes_buf); if (len < 0) { PySSL_SetError(self, len, __FILE__, __LINE__); return NULL; } /* this is actually an immutable bytes sequence */ retval = PyBytes_FromStringAndSize ((const char *) bytes_buf, len); OPENSSL_free(bytes_buf); return retval; } else { verification = SSL_CTX_get_verify_mode(self->ctx); if ((verification & SSL_VERIFY_PEER) == 0) return PyDict_New(); else return _decode_certificate (self->peer_cert, 0); } }
static PyObject *PySSL_SSLdo_handshake(PySSLObject *self) { int ret; int err; int sockstate; /* Actually negotiate SSL connection */ /* XXX If SSL_do_handshake() returns 0, it's also a failure. */ sockstate = 0; do { PySocketSockObject *sock = (PySocketSockObject *) PyWeakref_GetObject(self->Socket); if (((PyObject*)sock) == Py_None) { _setSSLError("Underlying socket connection gone", PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); return NULL; } PySSL_BEGIN_ALLOW_THREADS ret = SSL_do_handshake(self->ssl); err = SSL_get_error(self->ssl, ret); PySSL_END_ALLOW_THREADS if(PyErr_CheckSignals()) { return NULL; } if (err == SSL_ERROR_WANT_READ) { sockstate = check_socket_and_wait_for_timeout(sock, 0); } else if (err == SSL_ERROR_WANT_WRITE) { sockstate = check_socket_and_wait_for_timeout(sock, 1); } else { sockstate = SOCKET_OPERATION_OK; } if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, ERRSTR("The handshake operation timed out")); return NULL; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { PyErr_SetString(PySSLErrorObject, ERRSTR("Underlying socket has been closed.")); return NULL; } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { PyErr_SetString(PySSLErrorObject, ERRSTR("Underlying socket too large for select().")); return NULL; } else if (sockstate == SOCKET_IS_NONBLOCKING) { break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (ret < 1) return PySSL_SetError(self, ret, __FILE__, __LINE__); self->ssl->debug = 1; if (self->peer_cert) X509_free (self->peer_cert); PySSL_BEGIN_ALLOW_THREADS self->peer_cert = SSL_get_peer_certificate(self->ssl); PySSL_END_ALLOW_THREADS Py_INCREF(Py_None); return Py_None; }
static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) { PyObject *dest = NULL; Py_buffer buf; int buf_passed = 0; int count = -1; char *mem; /* XXX this should use Py_ssize_t */ int len = 1024; int sockstate; int err; int nonblocking; PySocketSockObject *sock = (PySocketSockObject *) PyWeakref_GetObject(self->Socket); if (((PyObject*)sock) == Py_None) { _setSSLError("Underlying socket connection gone", PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); return NULL; } if (!PyArg_ParseTuple(args, "|Oi:read", &dest, &count)) return NULL; if ((dest == NULL) || (dest == Py_None)) { if (!(dest = PyByteArray_FromStringAndSize((char *) 0, len))) return NULL; mem = PyByteArray_AS_STRING(dest); } else if (PyLong_Check(dest)) { len = PyLong_AS_LONG(dest); if (!(dest = PyByteArray_FromStringAndSize((char *) 0, len))) return NULL; mem = PyByteArray_AS_STRING(dest); } else { if (PyObject_GetBuffer(dest, &buf, PyBUF_CONTIG) < 0) return NULL; mem = buf.buf; len = buf.len; if ((count > 0) && (count <= len)) len = count; buf_passed = 1; } /* just in case the blocking state of the socket has been changed */ nonblocking = (sock->sock_timeout >= 0.0); BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); /* first check if there are bytes ready to be read */ PySSL_BEGIN_ALLOW_THREADS count = SSL_pending(self->ssl); PySSL_END_ALLOW_THREADS if (!count) { sockstate = check_socket_and_wait_for_timeout(sock, 0); if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The read operation timed out"); goto error; } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { PyErr_SetString(PySSLErrorObject, "Underlying socket too large for select()."); goto error; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { count = 0; goto done; } } do { err = 0; PySSL_BEGIN_ALLOW_THREADS count = SSL_read(self->ssl, mem, len); err = SSL_get_error(self->ssl, count); PySSL_END_ALLOW_THREADS if (PyErr_CheckSignals()) goto error; if (err == SSL_ERROR_WANT_READ) { sockstate = check_socket_and_wait_for_timeout(sock, 0); } else if (err == SSL_ERROR_WANT_WRITE) { sockstate = check_socket_and_wait_for_timeout(sock, 1); } else if ((err == SSL_ERROR_ZERO_RETURN) && (SSL_get_shutdown(self->ssl) == SSL_RECEIVED_SHUTDOWN)) { count = 0; goto done; } else { sockstate = SOCKET_OPERATION_OK; } if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The read operation timed out"); goto error; } else if (sockstate == SOCKET_IS_NONBLOCKING) { break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (count <= 0) { PySSL_SetError(self, count, __FILE__, __LINE__); goto error; } done: if (!buf_passed) { PyObject *res = PyBytes_FromStringAndSize(mem, count); Py_DECREF(dest); return res; } else { PyBuffer_Release(&buf); return PyLong_FromLong(count); } error: if (!buf_passed) { Py_DECREF(dest); } else { PyBuffer_Release(&buf); } return NULL; }
static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) { char *data; int len; int count; int sockstate; int err; int nonblocking; PySocketSockObject *sock = (PySocketSockObject *) PyWeakref_GetObject(self->Socket); if (((PyObject*)sock) == Py_None) { _setSSLError("Underlying socket connection gone", PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); return NULL; } if (!PyArg_ParseTuple(args, "y#:write", &data, &count)) return NULL; /* just in case the blocking state of the socket has been changed */ nonblocking = (sock->sock_timeout >= 0.0); BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); sockstate = check_socket_and_wait_for_timeout(sock, 1); if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The write operation timed out"); return NULL; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); return NULL; } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { PyErr_SetString(PySSLErrorObject, "Underlying socket too large for select()."); return NULL; } do { err = 0; PySSL_BEGIN_ALLOW_THREADS len = SSL_write(self->ssl, data, count); err = SSL_get_error(self->ssl, len); PySSL_END_ALLOW_THREADS if(PyErr_CheckSignals()) { return NULL; } if (err == SSL_ERROR_WANT_READ) { sockstate = check_socket_and_wait_for_timeout(sock, 0); } else if (err == SSL_ERROR_WANT_WRITE) { sockstate = check_socket_and_wait_for_timeout(sock, 1); } else { sockstate = SOCKET_OPERATION_OK; } if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The write operation timed out"); return NULL; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); return NULL; } else if (sockstate == SOCKET_IS_NONBLOCKING) { break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (len > 0) return PyLong_FromLong(len); else return PySSL_SetError(self, len, __FILE__, __LINE__); }
static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) { PyObject *buf; int count = 0; int len = 1024; int sockstate; int err; if (!PyArg_ParseTuple(args, "|i:read", &len)) return NULL; if (!(buf = PyString_FromStringAndSize((char *) 0, len))) return NULL; /* first check if there are bytes ready to be read */ Py_BEGIN_ALLOW_THREADS count = SSL_pending(self->ssl); Py_END_ALLOW_THREADS if (!count) { sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The read operation timed out"); Py_DECREF(buf); return NULL; } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { PyErr_SetString(PySSLErrorObject, "Underlying socket too large for select()."); return NULL; } } do { err = 0; Py_BEGIN_ALLOW_THREADS count = SSL_read(self->ssl, PyString_AsString(buf), len); err = SSL_get_error(self->ssl, count); Py_END_ALLOW_THREADS if(PyErr_CheckSignals()) { Py_DECREF(buf); return NULL; } if (err == SSL_ERROR_WANT_READ) { sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); } else if (err == SSL_ERROR_WANT_WRITE) { sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); } else { sockstate = SOCKET_OPERATION_OK; } if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The read operation timed out"); Py_DECREF(buf); return NULL; } else if (sockstate == SOCKET_IS_NONBLOCKING) { break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (count <= 0) { Py_DECREF(buf); return PySSL_SetError(self, count); } if (count != len) _PyString_Resize(&buf, count); return buf; }
static PySSLObject * newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file) { PySSLObject *self; char *errstr = NULL; int ret; int err; int sockstate; self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ if (self == NULL) return NULL; memset(self->server, '\0', sizeof(char) * X509_NAME_MAXLEN); memset(self->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN); self->server_cert = NULL; self->ssl = NULL; self->ctx = NULL; self->Socket = NULL; if ((key_file && !cert_file) || (!key_file && cert_file)) { errstr = "Both the key & certificate files must be specified"; goto fail; } Py_BEGIN_ALLOW_THREADS self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ Py_END_ALLOW_THREADS if (self->ctx == NULL) { errstr = "SSL_CTX_new error"; goto fail; } if (key_file) { Py_BEGIN_ALLOW_THREADS ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file, SSL_FILETYPE_PEM); Py_END_ALLOW_THREADS if (ret < 1) { errstr = "SSL_CTX_use_PrivateKey_file error"; goto fail; } Py_BEGIN_ALLOW_THREADS ret = SSL_CTX_use_certificate_chain_file(self->ctx, cert_file); Py_END_ALLOW_THREADS SSL_CTX_set_options(self->ctx, SSL_OP_ALL); /* ssl compatibility */ if (ret < 1) { errstr = "SSL_CTX_use_certificate_chain_file error"; goto fail; } } Py_BEGIN_ALLOW_THREADS SSL_CTX_set_verify(self->ctx, SSL_VERIFY_NONE, NULL); /* set verify lvl */ self->ssl = SSL_new(self->ctx); /* New ssl struct */ Py_END_ALLOW_THREADS SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */ /* If the socket is in non-blocking mode or timeout mode, set the BIO * to non-blocking mode (blocking is the default) */ if (Sock->sock_timeout >= 0.0) { /* Set both the read and write BIO's to non-blocking mode */ BIO_set_nbio(SSL_get_rbio(self->ssl), 1); BIO_set_nbio(SSL_get_wbio(self->ssl), 1); } Py_BEGIN_ALLOW_THREADS SSL_set_connect_state(self->ssl); Py_END_ALLOW_THREADS /* Actually negotiate SSL connection */ /* XXX If SSL_connect() returns 0, it's also a failure. */ sockstate = 0; do { Py_BEGIN_ALLOW_THREADS ret = SSL_connect(self->ssl); err = SSL_get_error(self->ssl, ret); Py_END_ALLOW_THREADS if(PyErr_CheckSignals()) { goto fail; } if (err == SSL_ERROR_WANT_READ) { sockstate = check_socket_and_wait_for_timeout(Sock, 0); } else if (err == SSL_ERROR_WANT_WRITE) { sockstate = check_socket_and_wait_for_timeout(Sock, 1); } else { sockstate = SOCKET_OPERATION_OK; } if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySSLErrorObject, "The connect operation timed out"); goto fail; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); goto fail; } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { PyErr_SetString(PySSLErrorObject, "Underlying socket too large for select()."); goto fail; } else if (sockstate == SOCKET_IS_NONBLOCKING) { break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); if (ret <= 0) { PySSL_SetError(self, ret); goto fail; } self->ssl->debug = 1; Py_BEGIN_ALLOW_THREADS if ((self->server_cert = SSL_get_peer_certificate(self->ssl))) { X509_NAME_oneline(X509_get_subject_name(self->server_cert), self->server, X509_NAME_MAXLEN); X509_NAME_oneline(X509_get_issuer_name(self->server_cert), self->issuer, X509_NAME_MAXLEN); } Py_END_ALLOW_THREADS self->Socket = Sock; Py_INCREF(self->Socket); return self; fail: if (errstr) PyErr_SetString(PySSLErrorObject, errstr); Py_DECREF(self); return NULL; }