示例#1
0
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;
}
示例#2
0
    }

    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);