src/openvpn/ssl_polarssl.c
53f97e1e
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single TCP/UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
  *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
  *  Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program (see the file COPYING included with this
  *  distribution); if not, write to the Free Software Foundation, Inc.,
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /**
  * @file Control Channel PolarSSL Backend
  */
 
c110b289
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
53f97e1e
 #include "syshead.h"
31ea2ee4
 
9b33b5a4
 #if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL)
31ea2ee4
 
53f97e1e
 #include "errlevel.h"
 #include "ssl_backend.h"
 #include "buffer.h"
 #include "misc.h"
 #include "manage.h"
 #include "ssl_common.h"
 
 #include "ssl_verify_polarssl.h"
50d1fc0d
 #include <polarssl/pem.h>
53f97e1e
 
 void
 tls_init_lib()
 {
 }
 
 void
 tls_free_lib()
 {
 }
 
 void
 tls_clear_error()
 {
 }
 
50d1fc0d
 static int default_ciphersuites[] =
53f97e1e
 {
     SSL_EDH_RSA_AES_256_SHA,
     SSL_EDH_RSA_CAMELLIA_256_SHA,
     SSL_EDH_RSA_AES_128_SHA,
     SSL_EDH_RSA_CAMELLIA_128_SHA,
     SSL_EDH_RSA_DES_168_SHA,
     SSL_RSA_AES_256_SHA,
     SSL_RSA_CAMELLIA_256_SHA,
     SSL_RSA_AES_128_SHA,
     SSL_RSA_CAMELLIA_128_SHA,
     SSL_RSA_DES_168_SHA,
     SSL_RSA_RC4_128_SHA,
     SSL_RSA_RC4_128_MD5,
     0
 };
 
 void
 tls_ctx_server_new(struct tls_root_ctx *ctx)
 {
   ASSERT(NULL != ctx);
   CLEAR(*ctx);
 
   ALLOC_OBJ_CLEAR(ctx->hs, havege_state);
   havege_init(ctx->hs);
 
   ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
   ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context);
 
   ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_cert);
   ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_cert);
 
 
   ctx->endpoint = SSL_IS_SERVER;
   ctx->initialised = true;
 }
 
 void
 tls_ctx_client_new(struct tls_root_ctx *ctx)
 {
   ASSERT(NULL != ctx);
 
   CLEAR(*ctx);
 
   ALLOC_OBJ_CLEAR(ctx->hs, havege_state);
   havege_init(ctx->hs);
 
   ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
   ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context);
 
   ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_cert);
   ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_cert);
 
   ctx->endpoint = SSL_IS_CLIENT;
   ctx->initialised = true;
 }
 
 void
 tls_ctx_free(struct tls_root_ctx *ctx)
 {
   if (ctx)
     {
       rsa_free(ctx->priv_key);
       free(ctx->priv_key);
 
       x509_free(ctx->ca_chain);
       free(ctx->ca_chain);
 
       x509_free(ctx->crt_chain);
       free(ctx->crt_chain);
 
       dhm_free(ctx->dhm_ctx);
       free(ctx->dhm_ctx);
 
 #if defined(ENABLE_PKCS11)
       if (ctx->priv_key_pkcs11 != NULL) {
 	  pkcs11_priv_key_free(ctx->priv_key_pkcs11);
 	  free(ctx->priv_key_pkcs11);
       }
 #endif
 
       free(ctx->hs);
 
       if (ctx->allowed_ciphers)
 	free(ctx->allowed_ciphers);
 
       CLEAR(*ctx);
 
       ctx->initialised = false;
 
     }
 }
 
 bool
 tls_ctx_initialised(struct tls_root_ctx *ctx)
 {
   ASSERT(NULL != ctx);
   return ctx->initialised;
 }
 
 void
 tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
 {
 }
 
 void
 tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
 {
1d90851e
   char *tmp_ciphers, *tmp_ciphers_orig, *token;
53f97e1e
   int i, cipher_count;
   int ciphers_len = strlen (ciphers);
 
   ASSERT (NULL != ctx);
   ASSERT (0 != ciphers_len);
 
   /* Get number of ciphers */
   for (i = 0, cipher_count = 1; i < ciphers_len; i++)
     if (ciphers[i] == ':')
       cipher_count++;
 
   /* Allocate an array for them */
   ALLOC_ARRAY_CLEAR(ctx->allowed_ciphers, int, cipher_count+1)
 
   /* Parse allowed ciphers, getting IDs */
   i = 0;
   tmp_ciphers_orig = tmp_ciphers = strdup(ciphers);
1d90851e
 
   token = strtok (tmp_ciphers, ":");
   while(token)
     {
       ctx->allowed_ciphers[i] = ssl_get_ciphersuite_id (token);
       if (0 != ctx->allowed_ciphers[i])
53f97e1e
 	i++;
1d90851e
       token = strtok (NULL, ":");
     }
53f97e1e
   free(tmp_ciphers_orig);
 }
 
 void
 tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file
 #if ENABLE_INLINE_FILES
     , const char *dh_file_inline
 #endif /* ENABLE_INLINE_FILES */
     )
 {
 #if ENABLE_INLINE_FILES
   if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_file_inline)
     {
       if (0 != x509parse_dhm(ctx->dhm_ctx, dh_file_inline, strlen(dh_file_inline)))
 	msg (M_FATAL, "Cannot read inline DH parameters");
   }
 else
 #endif /* ENABLE_INLINE_FILES */
   {
     if (0 != x509parse_dhmfile(ctx->dhm_ctx, dh_file))
       msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file);
   }
 
c2896b10
   msg (D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with " counter_format " bit key",
       (counter_type) 8 * mpi_size(&ctx->dhm_ctx->P));
53f97e1e
 }
 
 int
 tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
 #if ENABLE_INLINE_FILES
     const char *pkcs12_file_inline,
 #endif /* ENABLE_INLINE_FILES */
     bool load_ca_file
     )
 {
   msg(M_FATAL, "PKCS #12 files not yet supported for PolarSSL.");
88133cdb
   return 0;
53f97e1e
 }
 
93c22ecc
 #ifdef ENABLE_CRYPTOAPI
53f97e1e
 void
 tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert)
 {
   msg(M_FATAL, "Windows CryptoAPI not yet supported for PolarSSL.");
 }
 #endif /* WIN32 */
 
 void
 tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
 #if ENABLE_INLINE_FILES
     const char *cert_file_inline,
 #endif
9b33b5a4
     openvpn_x509_cert_t **x509
53f97e1e
     )
 {
   ASSERT(NULL != ctx);
   if (NULL != x509)
     ASSERT(NULL == *x509);
 
 #if ENABLE_INLINE_FILES
   if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_file_inline)
     {
       if (0 != x509parse_crt(ctx->crt_chain, cert_file_inline,
 	  strlen(cert_file_inline)))
         msg (M_FATAL, "Cannot load inline certificate file");
     }
   else
 #endif /* ENABLE_INLINE_FILES */
     {
       if (0 != x509parse_crtfile(ctx->crt_chain, cert_file))
 	msg (M_FATAL, "Cannot load certificate file %s", cert_file);
     }
   if (x509)
     {
       *x509 = ctx->crt_chain;
     }
 }
 
47712706
 void
9b33b5a4
 tls_ctx_free_cert_file (openvpn_x509_cert_t *x509)
47712706
 {
   x509_free(x509);
 }
 
53f97e1e
 int
 tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file
 #if ENABLE_INLINE_FILES
     , const char *priv_key_file_inline
 #endif /* ENABLE_INLINE_FILES */
     )
 {
   int status;
   ASSERT(NULL != ctx);
 
 #if ENABLE_INLINE_FILES
   if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_file_inline)
     {
       status = x509parse_key(ctx->priv_key,
 	  priv_key_file_inline, strlen(priv_key_file_inline),
 	  NULL, 0);
50d1fc0d
       if (POLARSSL_ERR_PEM_PASSWORD_REQUIRED == status)
53f97e1e
 	{
 	  char passbuf[512] = {0};
 	  pem_password_callback(passbuf, 512, 0, NULL);
 	  status = x509parse_key(ctx->priv_key,
 	      priv_key_file_inline, strlen(priv_key_file_inline),
 	      passbuf, strlen(passbuf));
 	}
     }
   else
 #endif /* ENABLE_INLINE_FILES */
     {
       status = x509parse_keyfile(ctx->priv_key, priv_key_file, NULL);
50d1fc0d
       if (POLARSSL_ERR_PEM_PASSWORD_REQUIRED == status)
53f97e1e
 	{
 	  char passbuf[512] = {0};
 	  pem_password_callback(passbuf, 512, 0, NULL);
 	  status = x509parse_keyfile(ctx->priv_key, priv_key_file, passbuf);
 	}
     }
   if (0 != status)
     {
 #ifdef ENABLE_MANAGEMENT
50d1fc0d
       if (management && (POLARSSL_ERR_PEM_PASSWORD_MISMATCH == status))
53f97e1e
 	  management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
 #endif
       msg (M_WARN, "Cannot load private key file %s", priv_key_file);
       return 1;
     }
 
   warn_if_group_others_accessible (priv_key_file);
 
   /* TODO: Check Private Key */
cc8dd144
 #if 0
   if (!SSL_CTX_check_private_key (ctx))
     msg (M_SSLERR, "Private key does not match the certificate");
 #endif
53f97e1e
   return 0;
 }
 
 #ifdef MANAGMENT_EXTERNAL_KEY
 
 int
9b33b5a4
 tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, openvpn_x509_cert_t *cert)
53f97e1e
 {
   msg(M_FATAL, "Use of management external keys not yet supported for PolarSSL.");
5fa82c55
   return false;
53f97e1e
 }
 
 #endif
 
 void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
 #if ENABLE_INLINE_FILES
     const char *ca_file_inline,
 #endif
     const char *ca_path, bool tls_server
     )
 {
   if (ca_path)
       msg(M_FATAL, "ERROR: PolarSSL cannot handle the capath directive");
 
 #if ENABLE_INLINE_FILES
   if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline)
     {
       if (0 != x509parse_crt(ctx->ca_chain, ca_file_inline, strlen(ca_file_inline)));
 	msg (M_FATAL, "Cannot load inline CA certificates");
     }
   else
 #endif
     {
       /* Load CA file for verifying peer supplied certificate */
       if (0 != x509parse_crtfile(ctx->ca_chain, ca_file))
 	msg (M_FATAL, "Cannot load CA certificate file %s", ca_file);
     }
 }
 
 void
 tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file
 #if ENABLE_INLINE_FILES
     , const char *extra_certs_file_inline
 #endif
     )
 {
   ASSERT(NULL != ctx);
 
 #if ENABLE_INLINE_FILES
   if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline)
     {
       if (0 != x509parse_crt(ctx->crt_chain, extra_certs_file_inline,
 	  strlen(extra_certs_file_inline)))
         msg (M_FATAL, "Cannot load inline extra-certs file");
     }
   else
 #endif /* ENABLE_INLINE_FILES */
     {
       if (0 != x509parse_crtfile(ctx->crt_chain, extra_certs_file))
 	msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file);
     }
 }
 
 /* **************************************
  *
  * Key-state specific functions
  *
  ***************************************/
 
 /*
  * "Endless buffer"
  */
 
 static inline void buf_free_entry(buffer_entry *entry)
 {
   if (NULL != entry)
     {
       free(entry->data);
       free(entry);
     }
 }
 
 static void buf_free_entries(endless_buffer *buf)
 {
   while(buf->first_block)
     {
       buffer_entry *cur_block = buf->first_block;
       buf->first_block = cur_block->next_block;
       buf_free_entry(cur_block);
     }
   buf->last_block = NULL;
 }
 
50d1fc0d
 static int endless_buf_read( void * ctx, unsigned char * out, size_t out_len )
53f97e1e
 {
   endless_buffer *in = (endless_buffer *) ctx;
50d1fc0d
   size_t read_len = 0;
53f97e1e
 
   if (in->first_block == NULL)
50d1fc0d
     return POLARSSL_ERR_NET_WANT_READ;
53f97e1e
 
   while (in->first_block != NULL && read_len < out_len)
     {
       int block_len = in->first_block->length - in->data_start;
       if (block_len <= out_len - read_len)
 	{
 	  buffer_entry *cur_entry = in->first_block;
 	  memcpy(out + read_len, cur_entry->data + in->data_start,
 	      block_len);
 
 	  read_len += block_len;
 
 	  in->first_block = cur_entry->next_block;
 	  in->data_start = 0;
 
 	  if (in->first_block == NULL)
 	    in->last_block = NULL;
 
 	  buf_free_entry(cur_entry);
 	}
       else
 	{
 	  memcpy(out + read_len, in->first_block->data + in->data_start,
 	      out_len - read_len);
 	  in->data_start += out_len - read_len;
 	  read_len = out_len;
 	}
     }
 
   return read_len;
 }
 
eaacf8d8
 static int endless_buf_write( void *ctx, const unsigned char *in, size_t len )
53f97e1e
 {
   endless_buffer *out = (endless_buffer *) ctx;
   buffer_entry *new_block = malloc(sizeof(buffer_entry));
   if (NULL == new_block)
     return POLARSSL_ERR_NET_SEND_FAILED;
 
   new_block->data = malloc(len);
   if (NULL == new_block->data)
     {
       free(new_block);
       return POLARSSL_ERR_NET_SEND_FAILED;
     }
 
   new_block->length = len;
   new_block->next_block = NULL;
 
   memcpy(new_block->data, in, len);
 
   if (NULL == out->first_block)
     out->first_block = new_block;
 
   if (NULL != out->last_block)
     out->last_block->next_block = new_block;
 
   out->last_block = new_block;
 
   return len;
 }
 
 static void my_debug( void *ctx, int level, const char *str )
 {
   if (level == 1)
     {
       dmsg (D_HANDSHAKE_VERBOSE, "PolarSSL alert: %s", str);
     }
 }
 
 void key_state_ssl_init(struct key_state_ssl *ks_ssl,
     const struct tls_root_ctx *ssl_ctx, bool is_server, void *session)
 {
   ASSERT(NULL != ssl_ctx);
   ASSERT(ks_ssl);
   CLEAR(*ks_ssl);
 
   ALLOC_OBJ_CLEAR(ks_ssl->ctx, ssl_context);
   if (0 == ssl_init(ks_ssl->ctx))
     {
       /* Initialise SSL context */
       ssl_set_dbg (ks_ssl->ctx, my_debug, NULL);
       ssl_set_endpoint (ks_ssl->ctx, ssl_ctx->endpoint);
       ssl_set_rng (ks_ssl->ctx, havege_rand, ssl_ctx->hs);
       ALLOC_OBJ_CLEAR (ks_ssl->ssn, ssl_session);
       ssl_set_session (ks_ssl->ctx, 0, 0, ks_ssl->ssn );
       if (ssl_ctx->allowed_ciphers)
50d1fc0d
 	ssl_set_ciphersuites (ks_ssl->ctx, ssl_ctx->allowed_ciphers);
53f97e1e
       else
50d1fc0d
 	ssl_set_ciphersuites (ks_ssl->ctx, default_ciphersuites);
53f97e1e
 
       /* Initialise authentication information */
50d1fc0d
       if (is_server)
 	ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx );
a9bf901c
 #if defined(ENABLE_PKCS11)
53f97e1e
       if (ssl_ctx->priv_key_pkcs11 != NULL)
 	ssl_set_own_cert_pkcs11( ks_ssl->ctx, ssl_ctx->crt_chain,
 	    ssl_ctx->priv_key_pkcs11 );
       else
a9bf901c
 #endif
53f97e1e
 	ssl_set_own_cert( ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key );
 
       /* Initialise SSL verification */
       ssl_set_authmode (ks_ssl->ctx, SSL_VERIFY_REQUIRED);
       ssl_set_verify (ks_ssl->ctx, verify_callback, session);
       /* TODO: PolarSSL does not currently support sending the CA chain to the client */
       ssl_set_ca_chain (ks_ssl->ctx, ssl_ctx->ca_chain, NULL, NULL );
 
       /* Initialise BIOs */
       ALLOC_OBJ_CLEAR (ks_ssl->ct_in, endless_buffer);
       ALLOC_OBJ_CLEAR (ks_ssl->ct_out, endless_buffer);
       ssl_set_bio (ks_ssl->ctx, endless_buf_read, ks_ssl->ct_in,
 	  endless_buf_write, ks_ssl->ct_out);
 
     }
 }
 
 void
 key_state_ssl_free(struct key_state_ssl *ks_ssl)
 {
   if (ks_ssl) {
       if (ks_ssl->ctx)
 	{
 	  ssl_free(ks_ssl->ctx);
 	  free(ks_ssl->ctx);
 	}
       if (ks_ssl->ssn)
 	free(ks_ssl->ssn);
       if (ks_ssl->ct_in) {
 	buf_free_entries(ks_ssl->ct_in);
 	free(ks_ssl->ct_in);
       }
       if (ks_ssl->ct_out) {
 	buf_free_entries(ks_ssl->ct_out);
 	free(ks_ssl->ct_out);
       }
       CLEAR(*ks_ssl);
   }
 }
 
 int
 key_state_write_plaintext (struct key_state_ssl *ks, struct buffer *buf)
 {
   int retval = 0;
   perf_push (PERF_BIO_WRITE_PLAINTEXT);
 
   ASSERT (NULL != ks);
   ASSERT (buf);
   ASSERT (buf->len >= 0);
 
   if (0 == buf->len)
     {
       return 0;
       perf_pop ();
     }
 
   retval = ssl_write(ks->ctx, BPTR(buf), buf->len);
 
   if (retval < 0)
     {
       perf_pop ();
50d1fc0d
       if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
53f97e1e
 	return 0;
       msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_plaintext error");
       return -1;
     }
 
   if (retval != buf->len)
     {
       msg (D_TLS_ERRORS,
 	  "TLS ERROR: write tls_write_plaintext incomplete %d/%d",
 	  retval, buf->len);
       perf_pop ();
       return -1;
     }
 
   /* successful write */
   dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_plaintext %d bytes", retval);
 
   memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */
   buf->len = 0;
 
   perf_pop ();
   return 1;
 }
 
 int
 key_state_write_plaintext_const (struct key_state_ssl *ks, const uint8_t *data, int len)
 {
   int retval = 0;
   perf_push (PERF_BIO_WRITE_PLAINTEXT);
 
   ASSERT (NULL != ks);
   ASSERT (len >= 0);
 
   if (0 == len)
     {
       perf_pop ();
       return 0;
     }
 
   ASSERT (data);
 
   retval = ssl_write(ks->ctx, data, len);
 
   if (retval < 0)
     {
       perf_pop ();
50d1fc0d
       if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
53f97e1e
 	return 0;
       msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_plaintext_const error");
       return -1;
     }
 
   if (retval != len)
     {
       msg (D_TLS_ERRORS,
 	  "TLS ERROR: write tls_write_plaintext_const incomplete %d/%d",
 	  retval, len);
       perf_pop ();
       return -1;
     }
 
   /* successful write */
   dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_plaintext_const %d bytes", retval);
 
   perf_pop ();
   return 1;
 }
 
 int
 key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf,
     int maxlen)
 {
   int retval = 0;
   int len = 0;
 
   perf_push (PERF_BIO_READ_CIPHERTEXT);
 
   ASSERT (NULL != ks);
   ASSERT (buf);
   ASSERT (buf->len >= 0);
 
   if (buf->len)
     {
       perf_pop ();
       return 0;
     }
 
   len = buf_forward_capacity (buf);
   if (maxlen < len)
     len = maxlen;
 
   retval = endless_buf_read(ks->ct_out, BPTR(buf), len);
 
   /* Error during read, check for retry error */
   if (retval < 0)
     {
       perf_pop ();
50d1fc0d
       if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
53f97e1e
 	return 0;
       msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_plaintext error");
       buf->len = 0;
       return -1;
     }
   /* Nothing read, try again */
   if (0 == retval)
     {
       buf->len = 0;
       perf_pop ();
       return 0;
     }
 
   /* successful read */
   dmsg (D_HANDSHAKE_VERBOSE, "read tls_read_ciphertext %d bytes", retval);
   buf->len = retval;
   perf_pop ();
   return 1;
 }
 
 int
 key_state_write_ciphertext (struct key_state_ssl *ks, struct buffer *buf)
 {
   int retval = 0;
   perf_push (PERF_BIO_WRITE_CIPHERTEXT);
 
   ASSERT (NULL != ks);
   ASSERT (buf);
   ASSERT (buf->len >= 0);
 
   if (0 == buf->len)
     {
       perf_pop ();
       return 0;
     }
 
   retval = endless_buf_write(ks->ct_in, BPTR(buf), buf->len);
 
   if (retval < 0)
     {
       perf_pop ();
 
50d1fc0d
       if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
53f97e1e
 	return 0;
       msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_ciphertext error");
       return -1;
     }
 
   if (retval != buf->len)
     {
       msg (D_TLS_ERRORS,
 	  "TLS ERROR: write tls_write_ciphertext incomplete %d/%d",
 	  retval, buf->len);
       perf_pop ();
       return -1;
     }
 
   /* successful write */
   dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_ciphertext %d bytes", retval);
 
   memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */
   buf->len = 0;
 
   perf_pop ();
   return 1;
 }
 
 int
 key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf,
     int maxlen)
 {
   int retval = 0;
   int len = 0;
 
   perf_push (PERF_BIO_READ_PLAINTEXT);
 
   ASSERT (NULL != ks);
   ASSERT (buf);
   ASSERT (buf->len >= 0);
 
   if (buf->len)
     {
       perf_pop ();
       return 0;
     }
 
   len = buf_forward_capacity (buf);
   if (maxlen < len)
     len = maxlen;
 
   retval = ssl_read(ks->ctx, BPTR(buf), len);
 
   /* Error during read, check for retry error */
   if (retval < 0)
     {
50d1fc0d
       if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
53f97e1e
 	return 0;
       msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_plaintext error");
       buf->len = 0;
       perf_pop ();
       return -1;
     }
   /* Nothing read, try again */
   if (0 == retval)
     {
       buf->len = 0;
       perf_pop ();
       return 0;
     }
 
   /* successful read */
   dmsg (D_HANDSHAKE_VERBOSE, "read tls_read_plaintext %d bytes", retval);
   buf->len = retval;
 
   perf_pop ();
   return 1;
 }
 
 /* **************************************
  *
  * Information functions
  *
  * Print information for the end user.
  *
  ***************************************/
 void
 print_details (struct key_state_ssl * ks_ssl, const char *prefix)
 {
   x509_cert *cert;
   char s1[256];
   char s2[256];
 
   s1[0] = s2[0] = 0;
   openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s",
 		    prefix,
 		    ssl_get_version (ks_ssl->ctx),
50d1fc0d
 		    ssl_get_ciphersuite(ks_ssl->ctx));
53f97e1e
 
   cert = ks_ssl->ctx->peer_cert;
   if (cert != NULL)
     {
c2896b10
       openvpn_snprintf (s2, sizeof (s2), ", " counter_format " bit RSA", (counter_type) cert->rsa.len * 8);
53f97e1e
     }
 
   msg (D_HANDSHAKE, "%s%s", s1, s2);
 }
 
 void
 show_available_tls_ciphers ()
 {
50d1fc0d
   const int *ciphers = ssl_list_ciphersuites();
53f97e1e
 
 #ifndef ENABLE_SMALL
   printf ("Available TLS Ciphers,\n");
   printf ("listed in order of preference:\n\n");
 #endif
 
   while (*ciphers != 0)
     {
50d1fc0d
       printf ("%s\n", ssl_get_ciphersuite_name(*ciphers));
53f97e1e
       ciphers++;
     }
   printf ("\n");
 }
 
 void
 get_highest_preference_tls_cipher (char *buf, int size)
 {
   const char *cipher_name;
50d1fc0d
   const int *ciphers = ssl_list_ciphersuites();
53f97e1e
   if (*ciphers == 0)
     msg (M_FATAL, "Cannot retrieve list of supported SSL ciphers.");
 
50d1fc0d
   cipher_name = ssl_get_ciphersuite_name(*ciphers);
53f97e1e
   strncpynt (buf, cipher_name, size);
 }
31ea2ee4
 
9b33b5a4
 #endif /* defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL) */