bool sslLoop(SSL *ssl, int fd, bool isserver, bool verify, bool waitforpeer) { char inbuffer[NBYTES+1]; // Want to null terminate char netbuffer[NBYTES]; size_t insize = 0, instart = 0; bool read_wantwrite = false; // set if last read return want_write bool write_wantread = false; // set if last write returned want_read bool closed = false; // stdin has closed terminated = false; // global flag set by signal handler while (!terminated || SSL_renegotiate_pending(ssl)) { bool write_pending = insize > 0; fd_set rfds, wfds; FD_ZERO(&rfds); FD_ZERO(&wfds); // Suppress ingest of data if we are renegotiating & we are the server if (!closed && !write_pending && (!isserver || !SSL_renegotiate_pending(ssl))) { FD_SET(0, &rfds); } if (write_pending) { if (write_wantread) { FD_SET(fd, &rfds); } else { FD_SET(fd, &wfds); } } else if (!read_wantwrite) { FD_SET(fd, &rfds); } else { FD_SET(fd, &wfds); } { int ret = select(fd+1,&rfds,&wfds,NULL,NULL); if (ret < 0 && errno == EINTR) continue; // Recheck loop condition select_count++; CHECK(ret >= 0); } if (FD_ISSET(0, &rfds)) { size_t ret = read(0, inbuffer,NBYTES); if (debuglevel > 4) fprintf(stderr,"Read %zd bytes from 0\n", ret); CHECK(ret >= 0); if (ret <= 0) { closed = true; if (!waitforpeer) return true; } else { inbuffer[ret] = 0; if (strcmp(inbuffer, "r\n") == 0) { if (!renegotiatefull(ssl,isserver)) return false; } else { insize = ret; instart = 0; } } } bool gotsslevent = FD_ISSET(fd, &rfds) || FD_ISSET(fd, &wfds); // If we aren't waiting to complete a write we must be waiting to read. // If we are waiting to complete a write, we mustn't read as the // OpenSSL state machine cannae take it. if (!write_pending && gotsslevent) { while (true) { int ret = SSL_read(ssl, netbuffer, NBYTES); int err = SSL_get_error(ssl,ret); if (ret == 0) { return err == SSL_ERROR_ZERO_RETURN; } else if (ret > 0) { CHECK(err == SSL_ERROR_NONE); if (debuglevel > 4) fprintf(stderr,"Read %d bytes from SSL\n", ret); read_ok_count++; nread += ret; if (!noecho) CHECK(write(1,netbuffer,ret) > 0); if (verify) { // On first read from client, do client verification assert(isserver); verify = false; if (debuglevel > 2) fprintf(stderr,"Verifying client\n"); SSL_set_verify(ssl, SSL_VERIFY_PEER | //SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verifyCallback); if (!renegotiatefull(ssl,isserver)) return false; if (debuglevel > 2) fprintf(stderr,"Client verified\n"); } } else { if (err == SSL_ERROR_WANT_READ) { read_wantread_count++; read_wantwrite = false; } else if (err == SSL_ERROR_WANT_WRITE) { read_wantwrite_count++; read_wantwrite = true; } else if (err == SSL_ERROR_SYSCALL && errno == EAGAIN) { // Don't do anything here, go round again. // This seems to be a new "feature". } else { fprintf(stderr, "SSL_read: err %d\n", err); CHECK(0); } break; // On error return } } } // We might have done some reads or writes to the socket in // the calls to SSL_read, so it's not clear that the various // flags are still valid at this point. So just // call SSL_write unconditionally & keep the logic simple (if we // didn't do a read, then we must have got the flags for write, if // we did, then the state might have changed), and if we didn't get // signalled on the SSL fd at all, we must have got something in // from stdin. // However, if write_pending is true, then we won't have tried // to read & it's only worth trying a write if we really got an // event on the SSL socket. I think. if (insize > 0 && !(write_pending && !gotsslevent)) { int ret = SSL_write(ssl, inbuffer+instart, insize); if (ret == 0) { return true; } else if (ret > 0) { if (debuglevel > 4) fprintf(stderr,"Write %d bytes to SSL\n", ret); // Allow for partial writes insize -= ret; instart += ret; nwritten += ret; write_wantread = false; write_ok_count++; } else { int err = SSL_get_error(ssl,ret); if (err == SSL_ERROR_WANT_READ) { write_wantread = true; write_wantread_count++; } else if (err == SSL_ERROR_WANT_WRITE) { write_wantread = false; write_wantwrite_count++; } else { fprintf(stderr,"SSL_write: err %d\n", err); CHECK(0); } } } // Now maybe start a random renegotiation if (!verify && insize == 0 && rfactor > 0 && rand()%rfactor == 0) { renegotiate_count++; if (!renegotiate(ssl,isserver)) return false; } } return true; }
} MY_BEGIN_ALLOW_THREADS(self->tstate); ret = SSL_renegotiate(self->ssl); MY_END_ALLOW_THREADS(self->tstate); if (PyErr_Occurred()) { flush_error_queue(); return NULL; } return PyLong_FromLong((long)ret); } static char ssl_Connection_do_handshake_doc[] = "\n\ Perform an SSL handshake (usually called after renegotiate() or one of\n\ set_*_state()). This can raise the same exceptions as send and recv.\n\ \n\ @return: None.\n\ "; static PyObject * ssl_Connection_do_handshake(ssl_ConnectionObj *self, PyObject *args) { int ret, err; if (!PyArg_ParseTuple(args, ":do_handshake")) return NULL; MY_BEGIN_ALLOW_THREADS(self->tstate); ret = SSL_do_handshake(self->ssl); MY_END_ALLOW_THREADS(self->tstate);