Blame doc/examples/tlsproxy/crypto-gnutls.c

Packit Service 4684c1
/*
Packit Service 4684c1
Packit Service 4684c1
The MIT License (MIT)
Packit Service 4684c1
Packit Service 4684c1
Copyright (c) 2016 Wrymouth Innovation Ltd
Packit Service 4684c1
Packit Service 4684c1
Permission is hereby granted, free of charge, to any person obtaining a
Packit Service 4684c1
copy of this software and associated documentation files (the "Software"),
Packit Service 4684c1
to deal in the Software without restriction, including without limitation
Packit Service 4684c1
the rights to use, copy, modify, merge, publish, distribute, sublicense,
Packit Service 4684c1
and/or sell copies of the Software, and to permit persons to whom the
Packit Service 4684c1
Software is furnished to do so, subject to the following conditions:
Packit Service 4684c1
Packit Service 4684c1
The above copyright notice and this permission notice shall be included
Packit Service 4684c1
in all copies or substantial portions of the Software.
Packit Service 4684c1
Packit Service 4684c1
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit Service 4684c1
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit Service 4684c1
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Packit Service 4684c1
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
Packit Service 4684c1
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
Packit Service 4684c1
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
Packit Service 4684c1
OTHER DEALINGS IN THE SOFTWARE.
Packit Service 4684c1
Packit Service 4684c1
*/
Packit Service 4684c1
Packit Service 4684c1
#include "config.h"
Packit Service 4684c1
Packit Service 4684c1
#include <errno.h>
Packit Service 4684c1
#include <fcntl.h>
Packit Service 4684c1
#include <string.h>
Packit Service 4684c1
#include <stdint.h>
Packit Service 4684c1
#include <stdio.h>
Packit Service 4684c1
#include <stdlib.h>
Packit Service 4684c1
#include <sys/select.h>
Packit Service 4684c1
#include <sys/socket.h>
Packit Service 4684c1
#include <sys/time.h>
Packit Service 4684c1
#include <sys/types.h>
Packit Service 4684c1
#include <unistd.h>
Packit Service 4684c1
Packit Service 4684c1
#include <gnutls/gnutls.h>
Packit Service 4684c1
#include <gnutls/crypto.h>
Packit Service 4684c1
#include <gnutls/x509.h>
Packit Service 4684c1
#include <gnutls/abstract.h>
Packit Service 4684c1
Packit Service 4684c1
#include "crypto-gnutls.h"
Packit Service 4684c1
#include "buffer.h"
Packit Service 4684c1
Packit Service 4684c1
#define FALSE 0
Packit Service 4684c1
#define TRUE 1
Packit Service 4684c1
Packit Service 4684c1
struct tlssession
Packit Service 4684c1
{
Packit Service 4684c1
  gnutls_certificate_credentials_t creds;
Packit Service 4684c1
  gnutls_session_t session;
Packit Service 4684c1
  char *hostname;
Packit Service 4684c1
  int (*quitfn) (void *opaque);
Packit Service 4684c1
  int (*erroutfn) (void *opaque, const char *format, va_list ap);
Packit Service 4684c1
  int debug;
Packit Service 4684c1
  void *opaque;
Packit Service 4684c1
};
Packit Service 4684c1
Packit Service 4684c1
#define BUF_SIZE 65536
Packit Service 4684c1
#define BUF_HWM ((BUF_SIZE*3)/4)
Packit Service 4684c1
Packit Service 4684c1
static int
Packit Service 4684c1
falsequit (void *opaque)
Packit Service 4684c1
{
Packit Service 4684c1
  return FALSE;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int
Packit Service 4684c1
quit (tlssession_t * s)
Packit Service 4684c1
{
Packit Service 4684c1
  return s->quitfn (s->opaque);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
#if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
Packit Service 4684c1
# pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
static int stderrout (void *opaque, const char *format, va_list ap)
Packit Service 4684c1
{
Packit Service 4684c1
  return vfprintf (stderr, format, ap);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int
Packit Service 4684c1
errout (tlssession_t * s, const char *format, ...)
Packit Service 4684c1
{
Packit Service 4684c1
  va_list ap;
Packit Service 4684c1
  int ret;
Packit Service 4684c1
  va_start (ap, format);
Packit Service 4684c1
  ret = s->erroutfn (s->opaque, format, ap);
Packit Service 4684c1
  va_end (ap);
Packit Service 4684c1
  return ret;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int
Packit Service 4684c1
debugout (tlssession_t * s, const char *format, ...)
Packit Service 4684c1
{
Packit Service 4684c1
  va_list ap;
Packit Service 4684c1
  int ret = 0;
Packit Service 4684c1
  va_start (ap, format);
Packit Service 4684c1
  if (s->debug)
Packit Service 4684c1
    ret = s->erroutfn (s->opaque, format, ap);
Packit Service 4684c1
  va_end (ap);
Packit Service 4684c1
  return ret;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int
Packit Service 4684c1
socksetnonblock (int fd, int nb)
Packit Service 4684c1
{
Packit Service 4684c1
  int sf = fcntl (fd, F_GETFL, 0);
Packit Service 4684c1
  if (sf == -1)
Packit Service 4684c1
    return -1;
Packit Service 4684c1
  return fcntl (fd, F_SETFL, nb ? (sf | O_NONBLOCK) : (sf & ~O_NONBLOCK));
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* From (public domain) example file in GNUTLS
Packit Service 4684c1
 *
Packit Service 4684c1
 * This function will try to verify the peer's certificate, and
Packit Service 4684c1
 * also check if the hostname matches, and the activation, expiration dates.
Packit Service 4684c1
 */
Packit Service 4684c1
static int
Packit Service 4684c1
verify_certificate_callback (gnutls_session_t session)
Packit Service 4684c1
{
Packit Service 4684c1
  unsigned int status;
Packit Service 4684c1
  int ret;
Packit Service 4684c1
  tlssession_t *s;
Packit Service 4684c1
Packit Service 4684c1
  /* read session pointer */
Packit Service 4684c1
  s = (tlssession_t *) gnutls_session_get_ptr (session);
Packit Service 4684c1
Packit Service 4684c1
  if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509)
Packit Service 4684c1
    return GNUTLS_E_CERTIFICATE_ERROR;
Packit Service 4684c1
Packit Service 4684c1
  /* This verification function uses the trusted CAs in the credentials
Packit Service 4684c1
   * structure. So you must have installed one or more CA certificates.
Packit Service 4684c1
   */
Packit Service 4684c1
  if (s->hostname && *s->hostname)
Packit Service 4684c1
    ret = gnutls_certificate_verify_peers3 (session, s->hostname, &status);
Packit Service 4684c1
  else
Packit Service 4684c1
    ret = gnutls_certificate_verify_peers2 (session, &status);
Packit Service 4684c1
Packit Service 4684c1
  if (ret < 0)
Packit Service 4684c1
    {
Packit Service 4684c1
      debugout (s, "Could not verfify peer certificate due to an error\n");
Packit Service 4684c1
      return GNUTLS_E_CERTIFICATE_ERROR;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  if (status)
Packit Service 4684c1
    {
Packit Service 4684c1
      gnutls_datum_t txt;
Packit Service 4684c1
      ret = gnutls_certificate_verification_status_print(status, GNUTLS_CRT_X509,
Packit Service 4684c1
							 &txt, 0);
Packit Service 4684c1
      if (ret >= 0)
Packit Service 4684c1
        {
Packit Service 4684c1
          debugout (s, "verification error: %s\n", txt.data);
Packit Service 4684c1
          gnutls_free(txt.data);
Packit Service 4684c1
        }
Packit Service 4684c1
Packit Service 4684c1
      return GNUTLS_E_CERTIFICATE_ERROR;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  debugout (s, "Peer passed certificate verification\n");
Packit Service 4684c1
Packit Service 4684c1
  /* notify gnutls to continue handshake normally */
Packit Service 4684c1
  return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
tlssession_t *
Packit Service 4684c1
tlssession_new (int isserver,
Packit Service 4684c1
		char *keyfile, char *certfile, char *cacertfile,
Packit Service 4684c1
		char *hostname, int insecure, int debug,
Packit Service 4684c1
		int (*quitfn) (void *opaque),
Packit Service 4684c1
		int (*erroutfn) (void *opaque, const char *format,
Packit Service 4684c1
				 va_list ap), void *opaque)
Packit Service 4684c1
{
Packit Service 4684c1
  int ret;
Packit Service 4684c1
  tlssession_t *s = calloc (1, sizeof (tlssession_t));
Packit Service 4684c1
  if (!s)
Packit Service 4684c1
    return NULL;
Packit Service 4684c1
Packit Service 4684c1
  if (quitfn)
Packit Service 4684c1
    s->quitfn = quitfn;
Packit Service 4684c1
  else
Packit Service 4684c1
    s->quitfn = falsequit;
Packit Service 4684c1
Packit Service 4684c1
  if (erroutfn)
Packit Service 4684c1
    s->erroutfn = erroutfn;
Packit Service 4684c1
  else
Packit Service 4684c1
    s->erroutfn = stderrout;
Packit Service 4684c1
Packit Service 4684c1
  if (hostname)
Packit Service 4684c1
    s->hostname = strdup (hostname);
Packit Service 4684c1
Packit Service 4684c1
  s->debug = debug;
Packit Service 4684c1
Packit Service 4684c1
  if (gnutls_certificate_allocate_credentials (&s->creds) < 0)
Packit Service 4684c1
    {
Packit Service 4684c1
      errout (s, "Certificate allocation memory error\n");
Packit Service 4684c1
      goto error;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  if (cacertfile != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      ret =
Packit Service 4684c1
	gnutls_certificate_set_x509_trust_file (s->creds, cacertfile,
Packit Service 4684c1
						GNUTLS_X509_FMT_PEM);
Packit Service 4684c1
      if (ret < 0)
Packit Service 4684c1
	{
Packit Service 4684c1
	  errout (s, "Error setting the x509 trust file: %s\n",
Packit Service 4684c1
		  gnutls_strerror (ret));
Packit Service 4684c1
	  goto error;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
      if (!insecure)
Packit Service 4684c1
	{
Packit Service 4684c1
	  gnutls_certificate_set_verify_function (s->creds,
Packit Service 4684c1
						  verify_certificate_callback);
Packit Service 4684c1
	  gnutls_certificate_set_verify_flags (s->creds,
Packit Service 4684c1
					       GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
Packit Service 4684c1
	}
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  if (keyfile && !certfile)
Packit Service 4684c1
    certfile = keyfile;
Packit Service 4684c1
Packit Service 4684c1
  if (certfile != NULL && keyfile != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      ret =
Packit Service 4684c1
	gnutls_certificate_set_x509_key_file (s->creds, certfile, keyfile,
Packit Service 4684c1
					      GNUTLS_X509_FMT_PEM);
Packit Service 4684c1
Packit Service 4684c1
      if (ret < 0)
Packit Service 4684c1
	{
Packit Service 4684c1
	  errout (s,
Packit Service 4684c1
		  "Error loading certificate or key file (%s, %s): %s\n",
Packit Service 4684c1
		  certfile, keyfile, gnutls_strerror (ret));
Packit Service 4684c1
	  goto error;
Packit Service 4684c1
	}
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  if (isserver)
Packit Service 4684c1
    ret = gnutls_init (&s->session, GNUTLS_SERVER);
Packit Service 4684c1
  else
Packit Service 4684c1
    ret = gnutls_init (&s->session, GNUTLS_CLIENT);
Packit Service 4684c1
Packit Service 4684c1
  if (ret < 0)
Packit Service 4684c1
    {
Packit Service 4684c1
      errout (s, "Cannot initialize GNUTLS session: %s\n",
Packit Service 4684c1
	      gnutls_strerror (ret));
Packit Service 4684c1
      goto error;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  gnutls_session_set_ptr (s->session, (void *) s);
Packit Service 4684c1
Packit Service 4684c1
  if (!isserver && s->hostname && *s->hostname)
Packit Service 4684c1
    {
Packit Service 4684c1
      ret = gnutls_server_name_set (s->session, GNUTLS_NAME_DNS, s->hostname,
Packit Service 4684c1
				    strlen (s->hostname));
Packit Service 4684c1
      if (ret < 0)
Packit Service 4684c1
        {
Packit Service 4684c1
          errout (s, "Cannot set server name: %s\n",
Packit Service 4684c1
	          gnutls_strerror (ret));
Packit Service 4684c1
          goto error;
Packit Service 4684c1
        }
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  ret = gnutls_set_default_priority (s->session);
Packit Service 4684c1
  if (ret < 0)
Packit Service 4684c1
    {
Packit Service 4684c1
      errout (s, "Cannot set default GNUTLS session priority: %s\n",
Packit Service 4684c1
	      gnutls_strerror (ret));
Packit Service 4684c1
      goto error;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  ret = gnutls_credentials_set (s->session, GNUTLS_CRD_CERTIFICATE, s->creds);
Packit Service 4684c1
  if (ret < 0)
Packit Service 4684c1
    {
Packit Service 4684c1
      errout (s, "Cannot set session GNUTL credentials: %s\n",
Packit Service 4684c1
	      gnutls_strerror (ret));
Packit Service 4684c1
      goto error;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  if (isserver)
Packit Service 4684c1
    {
Packit Service 4684c1
      /* requests but does not check a client certificate */
Packit Service 4684c1
      gnutls_certificate_server_set_request (s->session, GNUTLS_CERT_REQUEST);
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
  return s;
Packit Service 4684c1
Packit Service 4684c1
error:
Packit Service 4684c1
  if (s->session)
Packit Service 4684c1
    gnutls_deinit (s->session);
Packit Service 4684c1
  free (s);
Packit Service 4684c1
  return NULL;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
void
Packit Service 4684c1
tlssession_close (tlssession_t * s)
Packit Service 4684c1
{
Packit Service 4684c1
  if (s->session)
Packit Service 4684c1
    gnutls_deinit (s->session);
Packit Service 4684c1
  free (s->hostname);
Packit Service 4684c1
  free (s);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
tlssession_init (void)
Packit Service 4684c1
{
Packit Service 4684c1
  return gnutls_global_init ();
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
tlssession_mainloop (int cryptfd, int plainfd, tlssession_t * s)
Packit Service 4684c1
{
Packit Service 4684c1
  fd_set readfds;
Packit Service 4684c1
  fd_set writefds;
Packit Service 4684c1
  int maxfd;
Packit Service 4684c1
  int tls_wr_interrupted = 0;
Packit Service 4684c1
  int plainEOF = FALSE;
Packit Service 4684c1
  int cryptEOF = FALSE;
Packit Service 4684c1
  ssize_t ret;
Packit Service 4684c1
Packit Service 4684c1
  buffer_t *plainToCrypt = bufNew (BUF_SIZE, BUF_HWM);
Packit Service 4684c1
  buffer_t *cryptToPlain = bufNew (BUF_SIZE, BUF_HWM);
Packit Service 4684c1
Packit Service 4684c1
  if (socksetnonblock (cryptfd, 0) < 0)
Packit Service 4684c1
    {
Packit Service 4684c1
      errout (s, "Could not turn on blocking: %m");
Packit Service 4684c1
      goto error;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  /* set it up to work with our FD */
Packit Service 4684c1
  gnutls_transport_set_ptr (s->session,
Packit Service 4684c1
			    (gnutls_transport_ptr_t) (intptr_t) cryptfd);
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
  /* Now do the handshake */
Packit Service 4684c1
  ret = gnutls_handshake (s->session);
Packit Service 4684c1
  if (ret < 0)
Packit Service 4684c1
    {
Packit Service 4684c1
      errout (s, "TLS handshake failed: %s\n", gnutls_strerror (ret));
Packit Service 4684c1
      goto error;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  if (socksetnonblock (cryptfd, 1) < 0)
Packit Service 4684c1
    {
Packit Service 4684c1
      errout (s, "Could not turn on non-blocking on crypt FD: %m");
Packit Service 4684c1
      goto error;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  if (socksetnonblock (plainfd, 1) < 0)
Packit Service 4684c1
    {
Packit Service 4684c1
      errout (s, "Could not turn on non-blocking on plain FD: %m");
Packit Service 4684c1
      goto error;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  maxfd = (plainfd > cryptfd) ? plainfd + 1 : cryptfd + 1;
Packit Service 4684c1
Packit Service 4684c1
  while ((!plainEOF || !cryptEOF) && !quit (s))
Packit Service 4684c1
    {
Packit Service 4684c1
      struct timeval timeout;
Packit Service 4684c1
      int result;
Packit Service 4684c1
      int selecterrno;
Packit Service 4684c1
      int wait = TRUE;
Packit Service 4684c1
Packit Service 4684c1
      FD_ZERO (&readfds);
Packit Service 4684c1
      FD_ZERO (&writefds);
Packit Service 4684c1
Packit Service 4684c1
      size_t buffered = gnutls_record_check_pending (s->session);
Packit Service 4684c1
      if (buffered)
Packit Service 4684c1
	wait = FALSE;		/* do not wait for select to return if we have buffered data */
Packit Service 4684c1
Packit Service 4684c1
      if (plainEOF)
Packit Service 4684c1
	{
Packit Service 4684c1
	  /* plain text end has closed, but me may still have
Packit Service 4684c1
	   * data yet to write to the crypt end */
Packit Service 4684c1
	  if (bufIsEmpty (plainToCrypt) && !tls_wr_interrupted)
Packit Service 4684c1
	    {
Packit Service 4684c1
	      cryptEOF = TRUE;
Packit Service 4684c1
	      break;
Packit Service 4684c1
	    }
Packit Service 4684c1
	}
Packit Service 4684c1
      else
Packit Service 4684c1
	{
Packit Service 4684c1
	  if (!bufIsEmpty (cryptToPlain))
Packit Service 4684c1
	    FD_SET (plainfd, &writefds);
Packit Service 4684c1
	  if (!bufIsOverHWM (plainToCrypt))
Packit Service 4684c1
	    FD_SET (plainfd, &readfds);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
      if (cryptEOF)
Packit Service 4684c1
	{
Packit Service 4684c1
	  /* crypt end has closed, but me way still have data to
Packit Service 4684c1
	   * write from the crypt buffer */
Packit Service 4684c1
	  if (bufIsEmpty (cryptToPlain) && !buffered)
Packit Service 4684c1
	    {
Packit Service 4684c1
	      plainEOF = TRUE;
Packit Service 4684c1
	      break;
Packit Service 4684c1
	    }
Packit Service 4684c1
	}
Packit Service 4684c1
      else
Packit Service 4684c1
	{
Packit Service 4684c1
	  if (!bufIsEmpty (plainToCrypt) || tls_wr_interrupted)
Packit Service 4684c1
	    FD_SET (cryptfd, &writefds);
Packit Service 4684c1
	  if (!bufIsOverHWM (cryptToPlain))
Packit Service 4684c1
	    FD_SET (cryptfd, &readfds);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
      /* Repeat select whilst EINTR happens */
Packit Service 4684c1
      do
Packit Service 4684c1
	{
Packit Service 4684c1
	  timeout.tv_sec = wait ? 1 : 0;
Packit Service 4684c1
	  timeout.tv_usec = 0;
Packit Service 4684c1
	  result = select (maxfd, &readfds, &writefds, NULL, &timeout);
Packit Service 4684c1
Packit Service 4684c1
	  selecterrno = errno;
Packit Service 4684c1
	}
Packit Service 4684c1
      while ((result == -1) && (selecterrno == EINTR) && !quit (s));
Packit Service 4684c1
      if (quit (s))
Packit Service 4684c1
	break;
Packit Service 4684c1
Packit Service 4684c1
      if (FD_ISSET (plainfd, &readfds))
Packit Service 4684c1
	{
Packit Service 4684c1
	  /* we can read at least one byte */
Packit Service 4684c1
	  void *addr = NULL;
Packit Service 4684c1
	  /* get a span of characters to write to the
Packit Service 4684c1
	   * buffer. As the empty portion may wrap the end of the
Packit Service 4684c1
	   * circular buffer this might not be all we could read.
Packit Service 4684c1
	   */
Packit Service 4684c1
	  ssize_t len = bufGetWriteSpan (plainToCrypt, &addr);
Packit Service 4684c1
	  if (len > 0)
Packit Service 4684c1
	    {
Packit Service 4684c1
	      do
Packit Service 4684c1
		{
Packit Service 4684c1
		  ret = read (plainfd, addr, (size_t) len);
Packit Service 4684c1
		}
Packit Service 4684c1
	      while ((ret < 0) && (errno == EINTR) && !quit (s));
Packit Service 4684c1
	      if (quit (s))
Packit Service 4684c1
		break;
Packit Service 4684c1
	      if (ret < 0)
Packit Service 4684c1
		{
Packit Service 4684c1
		  errout (s, "Error on read from plain socket: %m\n");
Packit Service 4684c1
		  goto error;
Packit Service 4684c1
		}
Packit Service 4684c1
	      if (ret == 0)
Packit Service 4684c1
		{
Packit Service 4684c1
		  plainEOF = TRUE;
Packit Service 4684c1
		}
Packit Service 4684c1
	      else
Packit Service 4684c1
		{
Packit Service 4684c1
		  bufDoneWrite (plainToCrypt, ret);	/* mark ret bytes as written to the buffer */
Packit Service 4684c1
		}
Packit Service 4684c1
	    }
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
      if (FD_ISSET (plainfd, &writefds))
Packit Service 4684c1
	{
Packit Service 4684c1
	  /* we can write at least one byte */
Packit Service 4684c1
	  void *addr = NULL;
Packit Service 4684c1
	  /* get a span of characters to read from the buffer
Packit Service 4684c1
	   * as the full portion may wrap the end of the circular buffer
Packit Service 4684c1
	   * this might not be all we have to write.
Packit Service 4684c1
	   */
Packit Service 4684c1
	  ssize_t len = bufGetReadSpan (cryptToPlain, &addr);
Packit Service 4684c1
	  if (len > 0)
Packit Service 4684c1
	    {
Packit Service 4684c1
	      do
Packit Service 4684c1
		{
Packit Service 4684c1
		  ret = write (plainfd, addr, (size_t) len);
Packit Service 4684c1
		}
Packit Service 4684c1
	      while ((ret < 0) && (errno == EINTR) && !quit (s));
Packit Service 4684c1
	      if (quit (s))
Packit Service 4684c1
		break;
Packit Service 4684c1
	      if (ret < 0)
Packit Service 4684c1
		{
Packit Service 4684c1
		  errout (s, "Error on write to plain socket: %m\n");
Packit Service 4684c1
		  goto error;
Packit Service 4684c1
		}
Packit Service 4684c1
	      bufDoneRead (cryptToPlain, ret);	/* mark ret bytes as read from the buffer */
Packit Service 4684c1
	    }
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
      if (FD_ISSET (cryptfd, &readfds) || buffered)
Packit Service 4684c1
	{
Packit Service 4684c1
	  /* we can read at least one byte */
Packit Service 4684c1
	  void *addr = NULL;
Packit Service 4684c1
	  /* get a span of characters to write to the
Packit Service 4684c1
	   * buffer. As the empty portion may wrap the end of the
Packit Service 4684c1
	   * circular buffer this might not be all we could read.
Packit Service 4684c1
	   */
Packit Service 4684c1
	  ssize_t len = bufGetWriteSpan (cryptToPlain, &addr);
Packit Service 4684c1
	  if (len > 0)
Packit Service 4684c1
	    {
Packit Service 4684c1
	      do
Packit Service 4684c1
		{
Packit Service 4684c1
		  ret = gnutls_record_recv (s->session, addr, (size_t) len);
Packit Service 4684c1
		}
Packit Service 4684c1
	      while (ret == GNUTLS_E_INTERRUPTED && !quit (s));
Packit Service 4684c1
	      /* do not loop on GNUTLS_E_AGAIN - this means we'd block so we'd loop for
Packit Service 4684c1
	       * ever
Packit Service 4684c1
	       */
Packit Service 4684c1
	      if (quit (s))
Packit Service 4684c1
		break;
Packit Service 4684c1
	      if (ret < 0 && ret != GNUTLS_E_AGAIN)
Packit Service 4684c1
		{
Packit Service 4684c1
		  errout (s, "Error on read from crypt socket: %s\n",
Packit Service 4684c1
			  gnutls_strerror (ret));
Packit Service 4684c1
		  goto error;
Packit Service 4684c1
		}
Packit Service 4684c1
	      if (ret == 0)
Packit Service 4684c1
		{
Packit Service 4684c1
		  cryptEOF = TRUE;
Packit Service 4684c1
		}
Packit Service 4684c1
	      else
Packit Service 4684c1
		{
Packit Service 4684c1
		  bufDoneWrite (cryptToPlain, ret);	/* mark ret bytes as written to the buffer */
Packit Service 4684c1
		}
Packit Service 4684c1
	    }
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
      if (FD_ISSET (cryptfd, &writefds))
Packit Service 4684c1
	{
Packit Service 4684c1
	  /* we can write at least one byte */
Packit Service 4684c1
	  void *addr = NULL;
Packit Service 4684c1
	  /* get a span of characters to read from the buffer
Packit Service 4684c1
	   * as the full portion may wrap the end of the circular buffer
Packit Service 4684c1
	   * this might not be all we have to write.
Packit Service 4684c1
	   */
Packit Service 4684c1
	  ssize_t len = bufGetReadSpan (plainToCrypt, &addr);
Packit Service 4684c1
	  if (len > 0)
Packit Service 4684c1
	    {
Packit Service 4684c1
	      do
Packit Service 4684c1
		{
Packit Service 4684c1
		  if (tls_wr_interrupted)
Packit Service 4684c1
		    {
Packit Service 4684c1
		      ret = gnutls_record_send (s->session, NULL, 0);
Packit Service 4684c1
		    }
Packit Service 4684c1
		  else
Packit Service 4684c1
		    {
Packit Service 4684c1
		      ret = gnutls_record_send (s->session, addr, len);
Packit Service 4684c1
		    }
Packit Service 4684c1
		}
Packit Service 4684c1
	      while (ret == GNUTLS_E_INTERRUPTED && !quit (s));
Packit Service 4684c1
	      if (quit (s))
Packit Service 4684c1
		break;
Packit Service 4684c1
	      if (ret == GNUTLS_E_AGAIN)
Packit Service 4684c1
		{
Packit Service 4684c1
		  /* we need to call this again with NULL parameters
Packit Service 4684c1
		   * as it blocked
Packit Service 4684c1
		   */
Packit Service 4684c1
		  tls_wr_interrupted = TRUE;
Packit Service 4684c1
		}
Packit Service 4684c1
	      else if (ret < 0)
Packit Service 4684c1
		{
Packit Service 4684c1
		  errout (s, "Error on write to crypto socket: %s\n",
Packit Service 4684c1
			  gnutls_strerror (ret));
Packit Service 4684c1
		  goto error;
Packit Service 4684c1
		}
Packit Service 4684c1
	      else
Packit Service 4684c1
		{
Packit Service 4684c1
		  bufDoneRead (plainToCrypt, ret);	/* mark ret bytes as read from the buffer */
Packit Service 4684c1
		}
Packit Service 4684c1
	    }
Packit Service 4684c1
	}
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  ret = 0;
Packit Service 4684c1
  goto freereturn;
Packit Service 4684c1
Packit Service 4684c1
error:
Packit Service 4684c1
  ret = -1;
Packit Service 4684c1
Packit Service 4684c1
freereturn:
Packit Service 4684c1
  gnutls_bye (s->session, GNUTLS_SHUT_RDWR);
Packit Service 4684c1
  shutdown (plainfd, SHUT_RDWR);
Packit Service 4684c1
  bufFree (plainToCrypt);
Packit Service 4684c1
  bufFree (cryptToPlain);
Packit Service 4684c1
  return ret;
Packit Service 4684c1
}