Hello Adriaan,

I don't think that PolarSSL is so popular that we need to support
complex backward compatibility.

Supporting PolarSSL-1.1 should be sufficient, we can make the
configure script verify this minimum.

I also intend to work and cleanup the whole PolarSSL/OpenSSL mess...

Design will be to introduce crypto engine callback structure,
registering openssl and polarssl, in a way that code is using the
callback structure while using runtime configuration one can select
which engine to use (if both are available).

Are you interested in helping me? I have other major cleanups to do as well.

Alon.

On Mon, Apr 2, 2012 at 10:28 AM, Adriaan de Jong <dej...@fox-it.com> wrote:
>
> This patch, while retaining PolarSSL 1.0 support, introduces the PolarSSL
> 1.1 DRBG. This RNG adds a number of features, including support for
> personalisation strings and multiple entropy sources.
>
> Personalisation strings have been implemented, based on PID, program name,
> place within memory, and a hash of the user's certificate.
>
> The entropy sources used are the platform default ones. Which ones these
> are depends on how PolarSSL was built, but usually this includes:
>
>  - /dev/urandom or the Windows CryptoAPI RNG
>  - the HAVEGE RNG
>  - the output of PolarSSL's hardclock() call (usually RDTSC)
>
> Finally, this patch moves to only one instance of the RNG  per OpenVPN
> instance, instead of one per keystate
>
> Signed-off-by: Adriaan de Jong <dej...@fox-it.com>
> Signed-off-by: Eelse-jan Stutvoet <stutv...@fox-it.com>
> ---
>  src/openvpn/crypto_polarssl.c |   84
> ++++++++++++++++++++++++++++++++++++-----
>  src/openvpn/crypto_polarssl.h |   25 ++++++++++++
>  src/openvpn/ssl.c             |    5 ++
>  src/openvpn/ssl_backend.h     |   10 +++++
>  src/openvpn/ssl_polarssl.c    |   44 ++++++++++++++++-----
>  src/openvpn/ssl_polarssl.h    |    2 -
>  6 files changed, 148 insertions(+), 22 deletions(-)
>
> diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c
> index 0e6728c..158ccfc 100644
> --- a/src/openvpn/crypto_polarssl.c
> +++ b/src/openvpn/crypto_polarssl.c
> @@ -42,12 +42,18 @@
>  #include "buffer.h"
>  #include "integer.h"
>  #include "crypto_backend.h"
> +#include "otime.h"
> +#include "misc.h"
>
>  #include <polarssl/des.h>
>  #include <polarssl/md5.h>
>  #include <polarssl/cipher.h>
>  #include <polarssl/havege.h>
>
> +#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
> +#include <polarssl/entropy.h>
> +#endif
> +
>  /*
>  *
>  * Hardware engine support. Allows loading/unloading of engines.
> @@ -149,7 +155,6 @@ show_available_engines ()
>       "available\n");
>  }
>
> -
>  /*
>  *
>  * Random number functions, used in cases where we want
> @@ -159,29 +164,88 @@ show_available_engines ()
>  *
>  */
>
> -int
> -rand_bytes (uint8_t *output, int len)
> +/*
> + * Initialise the given ctr_drbg context, using a personalisation string
> and an
> + * entropy gathering function.
> + */
> +#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
> +ctr_drbg_context * rand_ctx_get()
> +{
> +  static entropy_context ec = {0};
> +  static ctr_drbg_context cd_ctx = {0};
> +  static bool rand_initialised = false;
> +
> +  if (!rand_initialised)
> +    {
> +      struct gc_arena gc = gc_new();
> +      struct buffer pers_string = alloc_buf_gc(100, &gc);
> +
> +      /*
> +       * Personalisation string, should be as unique as possible (see
> NIST
> +       * 800-90 section 8.7.1). We have very little information at this
> stage.
> +       * Include Program Name, memory address of the context and PID.
> +       */
> +      buf_printf(&pers_string, "OpenVPN %0u %p %s", platform_getpid(),
> &cd_ctx, time_string(0, 0, 0, &gc));
> +
> +      /* Initialise PolarSSL RNG, and built-in entropy sources */
> +      entropy_init(&ec);
> +
> +      if (0 != ctr_drbg_init(&cd_ctx, entropy_func, &ec,
> BPTR(&pers_string), BLEN(&pers_string)))
> +        msg (M_FATAL, "Failed to initialize random generator");
> +
> +      gc_free(&gc);
> +      rand_initialised = true;
> +  }
> +
> +  return &cd_ctx;
> +}
> +
> +#else /* (POLARSSL_VERSION_NUMBER < 0x01010000) */
> +
> +havege_state * rand_ctx_get()
>  {
>   static havege_state hs = {0};
> -  static bool hs_initialised = false;
> -  const int int_size = sizeof(int);
> +  static bool rand_initialised = false;
>
> -  if (!hs_initialised)
> +  if (!rand_initialised)
>     {
>       /* Initialise PolarSSL RNG */
>       havege_init(&hs);
> -      hs_initialised = true;
> +      rand_initialised = true;
>     }
>
> +  return &hs;
> +}
> +
> +#endif /* (POLARSSL_VERSION_NUMBER >= 0x01010000) */
> +
> +int
> +rand_bytes (uint8_t *output, int len)
> +{
> +#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
> +  ctr_drbg_context *rng_ctx = rand_ctx_get();
> +#else /* (POLARSSL_VERSION_NUMBER >= 0x01010000) */
> +  havege_state *rng_ctx = rand_ctx_get();
> +#endif /* (POLARSSL_VERSION_NUMBER >= 0x01010000) */
> +
>   while (len > 0)
>     {
> -      const int blen   = min_int (len, int_size);
> -      const int rand_int       = havege_rand(&hs);
> -
> +#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
> +      const size_t blen = min_int (len, CTR_DRBG_MAX_REQUEST);
> +      if (0 != ctr_drbg_random(rng_ctx, output, blen))
> +       return 0;
> +
> +#else /* (POLARSSL_VERSION_NUMBER >= 0x01010000) */
> +      const size_t blen = min_int (len, sizeof(int));
> +      const int rand_int = havege_rand(rng_ctx);
>       memcpy (output, &rand_int, blen);
> +
> +#endif /* (POLARSSL_VERSION_NUMBER >= 0x01010000) */
> +
>       output += blen;
>       len -= blen;
>     }
> +
>   return 1;
>  }
>
> diff --git a/src/openvpn/crypto_polarssl.h b/src/openvpn/crypto_polarssl.h
> index 358483a..2f303db 100644
> --- a/src/openvpn/crypto_polarssl.h
> +++ b/src/openvpn/crypto_polarssl.h
> @@ -30,9 +30,16 @@
>  #ifndef CRYPTO_POLARSSL_H_
>  #define CRYPTO_POLARSSL_H_
>
> +#include <polarssl/version.h>
>  #include <polarssl/cipher.h>
>  #include <polarssl/md.h>
>
> +#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
> +#  include <polarssl/ctr_drbg.h>
> +#else
> +#  include <polarssl/havege.h>
> +#endif
> +
>  /** Generic cipher key type %context. */
>  typedef cipher_info_t cipher_kt_t;
>
> @@ -71,4 +78,22 @@ typedef md_context_t hmac_ctx_t;
>  #define SHA_DIGEST_LENGTH      20
>  #define DES_KEY_LENGTH 8
>
> +/**
> + * Returns a singleton instance of the PolarSSL random number generator.
> + *
> + * For PolarSSL 1.0, this is the HAVEGE random number generator.
> + *
> + * For PolarSSL 1.1+, this is the CTR_DRBG random number generator. If it
> + * hasn't been initialised yet, the RNG will be initialised using the
> default
> + * entropy sources. Aside from the default platform entropy sources, an
> + * additional entropy source, the HAVEGE random number generator will
> also be
> + * added. During initialisation, a personalisation string will be added
> based
> + * on the time, the PID, and a pointer to the random context.
> + */
> +#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
> +ctr_drbg_context * rand_ctx_get();
> +#else
> +havege_state * rand_ctx_get();
> +#endif
> +
>  #endif /* CRYPTO_POLARSSL_H_ */
> diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
> index 251f8ed..767bc8e 100644
> --- a/src/openvpn/ssl.c
> +++ b/src/openvpn/ssl.c
> @@ -391,6 +391,11 @@ init_ssl (const struct options *options, struct
> tls_root_ctx *new_ctx)
>       tls_ctx_restrict_ciphers(new_ctx, options->cipher_list);
>     }
>
> +#ifdef ENABLE_CRYPTO_POLARSSL
> +  /* Fox-IT hardening: Personalise the random by mixing in the
> certificate */
> +  tls_ctx_personalise_random (new_ctx);
> +#endif
> +
>   tls_clear_error ();
>   return;
>
> diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h
> index 5ea6a06..f3e69dd 100644
> --- a/src/openvpn/ssl_backend.h
> +++ b/src/openvpn/ssl_backend.h
> @@ -272,6 +272,16 @@ void tls_ctx_load_extra_certs (struct tls_root_ctx
> *ctx, const char *extra_certs
>  #endif
>     );
>
> +#ifdef ENABLE_CRYPTO_POLARSSL
> +/**
> + * Add a personalisation string to the PolarSSL RNG, based on the
> certificate
> + * loaded into the given context.
> + *
> + * @param ctx                  TLS context to use
> + */
> +void tls_ctx_personalise_random(struct tls_root_ctx *ctx);
> +#endif
> +
>  /* **************************************
>  *
>  * Key-state specific functions
> diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c
> index d4d85c8..8f35608 100644
> --- a/src/openvpn/ssl_polarssl.c
> +++ b/src/openvpn/ssl_polarssl.c
> @@ -44,6 +44,9 @@
>  #include "manage.h"
>  #include "ssl_common.h"
>
> +#include <polarssl/sha2.h>
> +#include <polarssl/havege.h>
> +
>  #include "ssl_verify_polarssl.h"
>  #include <polarssl/pem.h>
>
> @@ -85,9 +88,6 @@ 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);
>
> @@ -103,12 +103,8 @@ 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);
>
> @@ -143,8 +139,6 @@ tls_ctx_free(struct tls_root_ctx *ctx)
>       }
>  #endif
>
> -      free(ctx->hs);
> -
>       if (ctx->allowed_ciphers)
>        free(ctx->allowed_ciphers);
>
> @@ -504,6 +498,30 @@ static void my_debug( void *ctx, int level, const
> char *str )
>     }
>  }
>
> +/*
> + * Further personalise the RNG using a hash of the public key
> + */
> +void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
> +{
> +#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
> +  static char old_sha256_hash[32] = {0};
> +  char sha256_hash[32] = {0};
> +  ctr_drbg_context *cd_ctx = rand_ctx_get();
> +
> +  if (NULL != ctx->crt_chain)
> +    {
> +      x509_cert *cert = ctx->crt_chain;
> +
> +      sha2(cert->tbs.p, cert->tbs.len, sha256_hash, false);
> +      if ( 0 != memcmp(old_sha256_hash, sha256_hash,
> sizeof(sha256_hash)))
> +       {
> +         ctr_drbg_update(cd_ctx, sha256_hash, 32);
> +         memcpy(old_sha256_hash, sha256_hash, sizeof(old_sha256_hash));
> +       }
> +    }
> +#endif /* POLARSSL_VERSION_NUMBER >= 0x01010000 */
> +}
> +
>  void key_state_ssl_init(struct key_state_ssl *ks_ssl,
>     const struct tls_root_ctx *ssl_ctx, bool is_server, void *session)
>  {
> @@ -517,7 +535,13 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
>       /* 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);
> +
> +#if (POLARSSL_VERSION_NUMBER >= 0x01010000)
> +      ssl_set_rng (ks_ssl->ctx, ctr_drbg_random, rand_ctx_get());
> +#else /* POLARSSL_VERSION_NUMBER >= 0x01010000 */
> +      ssl_set_rng (ks_ssl->ctx, havege_rand, rand_ctx_get());
> +#endif /* POLARSSL_VERSION_NUMBER >= 0x01010000 */
> +
>       ALLOC_OBJ_CLEAR (ks_ssl->ssn, ssl_session);
>       ssl_set_session (ks_ssl->ctx, 0, 0, ks_ssl->ssn );
>       if (ssl_ctx->allowed_ciphers)
> diff --git a/src/openvpn/ssl_polarssl.h b/src/openvpn/ssl_polarssl.h
> index e6149b6..2b02a6f 100644
> --- a/src/openvpn/ssl_polarssl.h
> +++ b/src/openvpn/ssl_polarssl.h
> @@ -30,7 +30,6 @@
>  #ifndef SSL_POLARSSL_H_
>  #define SSL_POLARSSL_H_
>
> -#include <polarssl/havege.h>
>  #include <polarssl/ssl.h>
>  #include "config.h"
>
> @@ -63,7 +62,6 @@ struct tls_root_ctx {
>
>     int endpoint;              /**< Whether or not this is a server or a
> client */
>
> -    havege_state *hs;          /**< HAVEGE random number state */
>     dhm_context *dhm_ctx;      /**< Diffie-Helmann-Merkle context */
>     x509_cert *crt_chain;      /**< Local Certificate chain */
>     x509_cert *ca_chain;       /**< CA chain for remote verification */
> --
> 1.7.5.4
>
>
>
> ------------------------------------------------------------------------------
> This SF email is sponsosred by:
> Try Windows Azure free for 90 days Click Here
> http://p.sf.net/sfu/sfd2d-msazure
> _______________________________________________
> Openvpn-devel mailing list
> Openvpn-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to